NewLang Project
Yet another programm language
Loading...
Searching...
No Matches
module_test.cpp
Go to the documentation of this file.
1#ifdef BUILD_UNITTEST
2
3#include "warning_push.h"
4#include <gtest/gtest.h>
5#include "warning_pop.h"
6
7#include "builtin.h"
8#include "runtime.h"
9
10using namespace newlang;
11
12/* Проблема совместного использования namespace и декораторов имен.
13 *
14 * Дектораторы имен ($ и @) импользуютсядля указания области видимости и времени жизни объектов.
15 * $ - локальные объекты, размещаемые "условно" на стеке. Удаляются по мере выхода из текущей области видимости.
16 * Локальный объект скрывает другие локальные и глобальные объекты с таким же именем.
17 * @ - глобальные объекты, размещаемые "условно" в куче и их время жизни не зависит от текущей области видимости.
18 * Глобальный объект заменяет другой глобальный объект с таким же именем.
19 *
20 * Namespace позволяют использовать одинаковые имена объектов разделяя для них области видимости,
21 * но можно ли совместить и использовтаь namespace и дектораторы одновременно?
22 *
23 * $local; @global;
24 * $name::local; \\name::global;
25 * но ns {
26 * $name::local; # Будет $ns::name::local
27 * \\name::global; # Все равно \\name::global или тоже \\ns::name::global ????
28 * }
29 * тогда без указания области видимости (без начального символа "::", т.е. name::var - объект выбирается автоматически,
30 * т.е. сперва ищется локальный объект с таким именем, потом глобальный)
31 * Какая разница между ::name::var и name::var?
32 * Первый в глобальной области видимости, второй в текущей?
33 *
34 * $var := 0; # ::var или $var
35 * @func() := {0}; # ::func или @func - 0
36 * name {
37 * $var := 1; # ::name::var
38 * $func() := {11}; # локальная с именем - ::name::func
39 * @func() := {111}; # глобальная с именем - @func
40 * \\name::func() := {1111}; # глобальная \\name::func и тоже самое, что и локальная $func() !!!
41 * name {
42 * var := 2; # ::name::name::var или $var или \\name::name::var
43 * @var := 2; # ::var
44 * \\name::name::var := 2; # ::name::name::var или \\name::name::var
45 * func() := {2}; # ::name::name::func или \\name::name::func - 2
46 * name3 {
47 * var := 3; # ::name::name::name3::var или $name::name::name3::var - 3
48 * func() := {3}; # ::name::name::name3::func или \\name::name::name3::func() - 3
49 *
50 * var??; # name::name::name3::var или $name::name::name3::var - 3
51 * name::var??; # name::name::var или \\name::name::var - 2
52 * name::name::var??; # name::var или \\name::name::var - 2
53 * ::name::var??; # name::var или $name::var - 1
54 * ::var??; # ::var или $var - 0
55 * }
56 * }
57 * }
58 * Предположим, что: <<<<<<<<<<<<<<< НЕ АКТУАЛЬНО после изменения ситаксиса мароксов !!!!!!!!!!!!!!!!!!!!!!!!!! >>>>>>>>>>>
59 * :: - глобальный корень. Может быть заменен на @ или $
60 * @@ — родительская функция после её переопределния
61 * $$ — родительский объект
62 * тогда:
63 * $$.field - поле родительского класса
64 * @@() - вызов переопределенной функции текущего класса или области видимости
65 * @func() []= {@@() + 10}; # @func - 10
66 * ::name::name@func
67 * \\name::name::func - такая запись ненравится, но будет самой правильной и логичной, так как все остальные еще хуже для понимания и разбора
68 * @::name::name::func
69 * @::name::name@func
70 * ::name::name::func@@
71 *
72 * <<<<<<<<<<<<<<<<<< НОВАЯ КОНЦЕПЦИЯ >>>>>>>>>>>>>>>>>>
73 *
74 * Все объекты физически размещаюится в куче, но время их жизни определяется областью видимости.
75 * Объекты с декораторами $ обозначают локальные объекты (аналог "на стеке") и они удаляются по мере выхода из текущей области видимости.
76 * Объекты с декораторами @ являются модулями или его объектами, доступны из других частй программы и сохраняют состояние при выходе из текущей области видимости.
77 *
78 * Указание модуля (имя файла) @file или @dir.file или @dir1.dir2.file
79 * Указание объекта в модуле @file::var или @dir.file::ns::func() или @dir.file::ns::obj.field; @file::ns:type @file::ns$local ???
80 *
81 * Файл модуля загружается однократно при первом обращении и не выгружается до явной команды???
82 * @module <*>;
83 * @dir.module2 <*>; # Импорт всех функций модуля (кроме начинающихся на подчерк)
84 * @dir.module2 <ns::name::*>; # Импорт всех функций из указанной области имен (кроме начинающихся на подчерк)
85 * @dir.module2 <map=ns::name::*>; # Импорт всех функций из указанной области имен с переименованием (кроме начинающихся на подчерк)
86 * @dir.module2 <func1, func2=::module2::ns::name::func2>; # Импорт только конкретных функций + переименование
87 * @dir.module2 <_>; # Выгрузить модуль?????
88 *
89 * \\ns ::name::space::long@\
90 * \ns::name;
91 *
92 * @dsl{}; # Загрузка модуля с определниями макросов для DSL в самом начале любой программы?
93 *
94 * @@ - главный модуль
95 * @$ - текущий модуль
96 * $$ - родительский объект (базовый объект или переопределяемая функция)
97 * $0 - текущий объект (this)
98 *
99 * [@$.__main__] --> { # 1 или 0
100 *
101 * }
102 * @$.__@@__ := {}; # Деструктор модуля
103 * __@@__ := {}; # Деструктор модуля
104 *
105 * \destructor() { // _____ ::=
106 * }
107 *
108 *
109 * Дектораторы имен ($ и @) импользуютсядля указания области видимости и времени жизни объектов.
110 * $ - локальные объекты, размещаемые "условно" на стеке. Удаляются по мере выхода из текущей области видимости.
111 * Локальный объект скрывает другие локальные и глобальные объекты с таким же именем.
112 * @ - глобальные объекты, размещаемые "условно" в куче и их время жизни не зависит от текущей области видимости.
113 * Глобальный объект заменяет другой глобальный объект с таким же именем.
114 *
115 * Namespace позволяют использовать одинаковые имена объектов разделяя для них области видимости,
116 * но можно ли совместить и использовтаь namespace и дектораторы одновременно?
117 *
118 *
119 * Наследование
120 * Часто композиция класса более подходяща, чем наследование. Когда используйте наследование, делайте его открытым (public).
121 * Когда дочерний класс наследуется от базового, он включает определения всех данных и операций от базового. "Наследование интерфейса" - это наследование от чистого абстрактного базового класса (в нём не определены состояние или методы). Всё остальное - это "наследование реализации".
122 * Наследование реализации уменьшает размер кода благодаря повторному использованию частей базового класса (который становится частью нового класса). Т.к. наследование является декларацией времени компиляции, это позволяет компилятору понимать структуру и находить ошибки. Наследование интерфейса может быть использовано чтобы класс поддерживал требуемый API. И также, компилятор может находить ошибки, если класс не определяет требуемый метод наследуемого API.
123 * В случае наследования реализации, код начинает размазываться между базовым и дочерним классом и это может усложнить понимание кода. Также, дочерний класс не может переопределять код невиртуальных функций (не может менять их реализацию).
124 * Множественное наследование ещё более проблемное, а также иногда приводит к уменьшению производительности. Часто просадка производительности при переходе от одиночного наследования к множественному может быть больше, чем переход от обычных функций к виртуальным. Также от множественного наследования один шаг до ромбического, а это уже ведёт к неопределённости, путанице и, конечно же, багам.
125 * Любое наследование должно быть открытым (public). Если хочется сделать закрытое (private), то лучше добавить новый член с экземпляром базового класса.
126 * Не злоупотребляйте наследованием реализации. Композиция классов часто более предпочтительна. Попытайтесь ограничить использование наследования семантикой "Является": Bar можно наследовать от Foo, если можно сказать, что Bar "Является" Foo (т.е. там, где используется Foo, можно также использовать и Bar).
127 * Защищёнными (protected) делайте лишь те функции, которые должны быть доступны для дочерних классов. Заметьте, что данные должны быть закрытыми (private).
128 * Явно декларируйте переопределение виртуальных функций/деструктора с помошью спецификаторов: либо override, либо (если требуется) final. Не используйте спецификатор virtual при переопределении функций. Объяснение: функция или деструктор, помеченные override или final, но не являющиеся виртуальными просто не скомпилируются (что помогает обнаружить общие ошибки). Также спецификаторы работают как документация; а если спецификаторов нет, то программист будет вынужден проверить всю иерархию, чтобы уточнить виртуальность функции.
129 * Множественное наследование <интерфейсов> допустимо, однако множественное наследование реализации не рекомендуется от слова совсем.
130 *
131 * Для замены множественного наследования можно исопльзовать оператор утиной типизации (сравнения интерфейсов)
132 *
133 * Конструкторы и деструкторы классов
134 *
135 * Конструктор у класса может быть только один - и это обычная функция с именем класса.
136 * Конструктор должен вернуть созданный экземпляр класса, который ему передается в $0 аргументе.
137 * Другие аргументы соотетствуют передаваемым при вызове конструктора.
138 * Конструктор по умолчанию принимает произвольное количество аргументов (для переопределения значения у
139 * свойств по время вызова конструтокра) и возвращает аргумент $0, т.е. constructor(...) :- {$0($*)};
140 * Пользователський конструтор лучше переопреелять в теле класса через оператор присвоения значения,
141 * аналог override, т.е. constructor(...) **=** {...}; (чтобы исключить ошибки в написании имени функции).
142 * Конструторы базовых классов автоматически не вызываются, и если это требуется по логике работы,
143 * то вызовы конструторов базовых классов необходимо выполнять вручную, например так: $0 = $$.base_constructor();
144 *
145 * Деструктор класса определяется в теле класса анонимной функицей (имя функци подчерк),
146 * т.е. _() :- {} и по умолчанию отсутствует. Деструткоры базовых классов вызываются автоматически?????
147 *
148 *
149 */
150
151llvm::orc::ThreadSafeModule createDemoModule();
152
153TEST(Module, CreateArc) {
154
155 if (!std::filesystem::exists(std::filesystem::path("temp"))) {
156 std::filesystem::create_directories(std::filesystem::path("temp"));
157 }
158 ASSERT_TRUE(std::filesystem::exists(std::filesystem::path("temp")));
159 ASSERT_TRUE(std::filesystem::is_directory(std::filesystem::path("temp")));
160
161
162 // str = AstAnalysis::MakeInclude(Parser::ParseString("::val := 1;"));
163 // ASSERT_STREQ("::val := ...;\n", str.c_str());
164 //
165 // str = AstAnalysis::MakeInclude(Parser::ParseString("::val := 1; val2 := 1; @::val3 := 1"));
166 // ASSERT_STREQ("::val := ...;\n@::val3 := ...;\n", str.c_str());
167 //
168 // str = AstAnalysis::MakeInclude(Parser::ParseString("::val, val2, @::val3 := 1"));
169 // ASSERT_STREQ("::val := ...;\n@::val3 := ...;\n", str.c_str());
170 //
171 // str = AstAnalysis::MakeInclude(Parser::ParseString("@@ macro @@ := 1; @@ macro2 @@ := @@ 2 @@; @@@@ macro @@@@;"));
172 // ASSERT_STREQ("@@ macro @@ := 1;\n@@ macro2 @@ := @@ 2 @@;\n@@@@ macro @@@@;\n", str.c_str());
173
174 std::string source = "::val := 1; val2 := 1; @::val3 := 1";
175 TermPtr ast = Parser::ParseString(source);
176 ASSERT_TRUE(ast);
177
178 RuntimePtr rt = RunTime::Init();
179
180 llvm::orc::ThreadSafeModule mod = createDemoModule();
181
182 std::filesystem::remove("temp/test-other.nlm");
183 std::filesystem::remove("temp/test-module.nlm");
184
185 FileModule module;
186
187 RunTime::ModuleCreate(module, "test-module", ast, source, mod.getModuleUnlocked());
188
189 ASSERT_TRUE(!module.name.empty());
190 ASSERT_STREQ("test-module", module.name.c_str());
191 ASSERT_TRUE(!module.include.empty());
192 ASSERT_TRUE(!module.source.empty());
193 ASSERT_TRUE(!module.bytecode.empty());
194
195 ASSERT_NO_THROW(
196 ASSERT_TRUE(RunTime::ModuleSave(module, "temp/test-other.nlm", "other"));
197 );
198 ASSERT_TRUE(std::filesystem::exists(std::filesystem::path("temp/test-other.nlm")));
199
200 ASSERT_NO_THROW(
201 ASSERT_TRUE(RunTime::ModuleSave(module, "temp/test-module.nlm"));
202 );
203 ASSERT_TRUE(std::filesystem::exists(std::filesystem::path("temp/test-module.nlm")));
204
205 FileModule module2;
206 RunTime::ModuleRead(module2, "temp/test-module.nlm");
207 ASSERT_TRUE(!module2.name.empty());
208 ASSERT_STREQ("test-module", module2.name.c_str());
209 ASSERT_EQ(module.include.size(), module2.include.size());
210 ASSERT_EQ(module.source.size(), module2.source.size());
211 ASSERT_EQ(module.bytecode.size(), module2.bytecode.size());
212 ASSERT_TRUE(0 == memcmp(module.bytecode.data(), module2.bytecode.data(), module2.bytecode.size()));
213
214 ASSERT_TRUE(0 == memcmp(module.source.data(), module2.source.data(), module2.source.size()));
215 ASSERT_TRUE(0 == memcmp(module.include.data(), module2.include.data(), module2.include.size()));
216 ASSERT_TRUE(0 == memcmp(module.bytecode.data(), module2.bytecode.data(), module2.bytecode.size()));
217
218
219 FileModule other;
220 RunTime::ModuleRead(other, "temp/test-other.nlm", "other");
221 ASSERT_TRUE(!other.name.empty());
222 ASSERT_STREQ("other", other.name.c_str());
223 ASSERT_EQ(module.include.size(), other.include.size());
224 ASSERT_EQ(module.source.size(), other.source.size());
225 ASSERT_EQ(module.bytecode.size(), other.bytecode.size());
226
227 ASSERT_TRUE(0 == memcmp(module.source.data(), other.source.data(), other.source.size()));
228 ASSERT_TRUE(0 == memcmp(module.include.data(), other.include.data(), other.include.size()));
229 ASSERT_TRUE(0 == memcmp(module.bytecode.data(), other.bytecode.data(), other.bytecode.size()));
230
231}
232//TEST(Module, Env) {
233//
234// const char *args[1] = {"--nlc-search=../example;../src"};
235//
236// RuntimePtr env = RunTime::Init(1, args);
237// // Context ctx(env);
238//
239// // env->CheckOrLoadModule("\\file");
240// // env->CheckOrLoadModule("\\dir\\file");
241// // env->CheckOrLoadModule("\\dir\\file::var");
242// // env->CheckOrLoadModule("\\dir\\file::var.ddd");
243//}
244//
245//TEST(Module, Load) {
246//
247// const char *args[1] = {"--nlc-search=./;../example;../src"};
248//
249// Context::Reset();
250//
251// RuntimePtr rt = RunTime::Init(1, args);
252// Context ctx(rt);
253//
254//
255// std::filesystem::create_directories("temp");
256// ASSERT_TRUE(std::filesystem::is_directory("temp"));
257//
258// std::ofstream file("temp/module_test.src");
259// file << "module_var1 := 1;\n";
260// file << "ns { module_var2 := 2;\n";
261// file << " ns2 { module_var3 := 3;};\n";
262// file << "};\n";
263// file << "ns3::ns4::module_var4 := 4;\n";
264// file.close();
265//
266// EXPECT_FALSE(ctx.FindSessionTerm("module_var1"));
267// EXPECT_FALSE(ctx.FindSessionTerm("ns::module_var2"));
268// EXPECT_FALSE(ctx.FindSessionTerm("ns::ns2::module_var3"));
269// EXPECT_FALSE(ctx.FindSessionTerm("ns3::ns4::module_var4"));
270//
271// TermPtr ast;
272// EXPECT_NO_THROW(ast = rt->GetParser()->Parse("var1:=1;\n \\temp\\module_test();\n var2:=2;"));
273// ASSERT_TRUE(ast);
274//
275// ModulePtr mod = rt->m_modules["\\temp\\module_test"];
276// ASSERT_TRUE(mod);
277//
278// ASSERT_TRUE(mod->find("$module_var1") != mod->end()) << mod->Dump();
279//
280//
281//
282//
283//
284//
285//
286//
287//
288//
289// EXPECT_ANY_THROW(
290// ctx.ExecStr("\\temp\\module_test::module_var1");
291// ) << ctx.Dump("; ");
292//
293// // Загрузить модуль и импортировать все объекты
294// ASSERT_STREQ("\\temp\\module_test", ExtractModuleName("\\temp\\module_test").c_str());
295//
296// ObjPtr result;
297// result = ctx.ExecStr("\\temp\\module_test()");
298// ASSERT_TRUE(result);
299// ASSERT_EQ(4, result->GetValueAsInteger()) << ctx.Dump("; ");
300//
301//
302// result = ctx.FindTerm("module_var1");
303// ASSERT_TRUE(result) << ctx.Dump("; ");
304// ASSERT_EQ(1, result->GetValueAsInteger());
305//
306// result = ctx.FindTerm("ns::module_var2");
307// ASSERT_TRUE(result) << ctx.Dump("; ");
308// ASSERT_EQ(2, result->GetValueAsInteger());
309//
310// result = ctx.FindTerm("\\temp\\module_test::ns::ns2::module_var3");
311// ASSERT_TRUE(result) << ctx.Dump("; ");
312// ASSERT_EQ(3, result->GetValueAsInteger());
313//
314// result = ctx.FindTerm("\\temp\\module_test::ns3::ns4::module_var4");
315// ASSERT_TRUE(result) << ctx.Dump("; ");
316// ASSERT_EQ(4, result->GetValueAsInteger());
317//
318//
319// ASSERT_TRUE(rt->m_modules.find("\\temp\\module_test") != rt->m_modules.end());
320//
321// // Выгрузить модуль
322// result = ctx.ExecStr("\\temp\\module_test(_)");
323// ASSERT_TRUE(result);
324//
325// ASSERT_TRUE(rt->m_modules.find("\\temp\\module_test") == rt->m_modules.end());
326//
327//
328// result = ctx.FindTerm("module_var1");
329// ASSERT_FALSE(result) << ctx.Dump("; ");
330// result = ctx.FindTerm("ns::module_var2");
331// ASSERT_FALSE(result) << ctx.Dump("; ");
332// result = ctx.FindTerm("ns::ns2::module_var3");
333// ASSERT_FALSE(result) << ctx.Dump("; ");
334// result = ctx.FindTerm("ns3::ns4::module_var4");
335// ASSERT_FALSE(result) << ctx.Dump("; ");
336//
337// EXPECT_ANY_THROW(
338// ctx.ExecStr("\\temp\\module_test::module_var1");
339// ) << ctx.Dump("; ");
340//
341// // Импортировать по маске
342// result = ctx.ExecStr("\\temp\\module_test('*')");
343// ASSERT_TRUE(result);
344// ASSERT_EQ(4, result->GetValueAsInteger()) << ctx.Dump("; ");
345//
346// result = ctx.FindTerm("ns::module_var2");
347// ASSERT_TRUE(result) << ctx.Dump("; ");
348// ASSERT_EQ(2, result->GetValueAsInteger()) << ctx.Dump("; ");
349//
350// result = ctx.FindTerm("\\temp\\module_test::ns::ns2::module_var3");
351// ASSERT_TRUE(result) << ctx.Dump("; ");
352// ASSERT_EQ(3, result->GetValueAsInteger()) << ctx.Dump("; ");
353//
354// ASSERT_TRUE(ctx.FindTerm("module_var1")) << ctx.Dump("; ");
355// ASSERT_TRUE(ctx.FindTerm("\\temp\\module_test::ns3::ns4::module_var4"));
356//
357//
358// ASSERT_TRUE(rt->m_modules.find("\\temp\\module_test") != rt->m_modules.end());
359//
360// // Выгрузить модуль
361// result = ctx.ExecStr("\\temp\\module_test(_)");
362// ASSERT_TRUE(result);
363//
364// ASSERT_TRUE(rt->m_modules.find("\\temp\\module_test") == rt->m_modules.end());
365//
366//
367// // // Импортировать по маске
368// // result = ctx.ExecStr("\\temp\\module_test('ns::*')");
369// // ASSERT_TRUE(result);
370// // ASSERT_EQ(4, result->GetValueAsInteger()) << ctx.Dump("; ");
371// //
372// // result = ctx.FindTerm("ns::module_var2");
373// // ASSERT_TRUE(result) << ctx.Dump("; ");
374// // ASSERT_EQ(2, result->GetValueAsInteger()) << ctx.Dump("; ");
375// //
376// // result = ctx.FindTerm("\\temp\\module_test::ns::ns2::module_var3");
377// // ASSERT_TRUE(result) << ctx.Dump("; ");
378// // ASSERT_EQ(3, result->GetValueAsInteger()) << ctx.Dump("; ");
379// //
380// // ASSERT_FALSE(ctx.FindTerm("module_var1")) << ctx.Dump("; ");
381// // ASSERT_FALSE(ctx.FindTerm("\\temp\\module_test::ns3::ns4::module_var4"));
382//
383//}
384//
385//TEST(Module, SysEnv) {
386//
387// const char *args[1] = {"--nlc-search=../example;../src"};
388//
389// Context::Reset();
390//
391// RuntimePtr env = RunTime::Init(1, args);
392// Context ctx(env);
393//
394//
395// std::filesystem::create_directories("temp");
396// ASSERT_TRUE(std::filesystem::is_directory("temp"));
397//
398// std::ofstream file("temp/module_test.src");
399// file << "module_var1 := 1;\n";
400// file << "ns { module_var2 := 2;\n";
401// file << " ns2 { module_var3 := 3;};\n";
402// file << "};\n";
403// file << "ns3::ns4::module_var4 := 4;\n";
404// file.close();
405//
406// EXPECT_FALSE(ctx.FindTerm("module_var1"));
407// EXPECT_FALSE(ctx.FindTerm("ns::module_var2"));
408// EXPECT_FALSE(ctx.FindTerm("ns::ns2::module_var3"));
409// EXPECT_FALSE(ctx.FindTerm("ns3::ns4::module_var4"));
410//
411// EXPECT_ANY_THROW(
412// ctx.ExecStr("\\temp\\module_test::module_var1");
413// ) << ctx.Dump("; ");
414//
415// // Загрузить модуль и импортировать все объекты
416// ASSERT_STREQ("\\temp\\module_test", ExtractModuleName("\\temp\\module_test").c_str());
417//
418// ObjPtr result;
419// ASSERT_NO_THROW(
420// result = ctx.ExecStr("\\temp\\module_test()");
421// );
422// ASSERT_TRUE(result);
423// ASSERT_EQ(4, result->GetValueAsInteger()) << ctx.Dump("; ");
424//
425// ASSERT_NO_THROW(
426// result = ctx.ExecStr("\\temp\\module_test::module_var1");
427// );
428// ASSERT_TRUE(result);
429// ASSERT_STREQ("1", result->GetValueAsString().c_str());
430//
431// ASSERT_NO_THROW(
432// result = ctx.ExecStr("\\temp\\module_test::__md5__");
433// );
434// ASSERT_TRUE(result);
435// ASSERT_EQ(32, result->GetValueAsString().size()) << result->GetValueAsString();
436//
437// ASSERT_NO_THROW(
438// result = ctx.ExecStr("\\temp\\module_test::__timestamp__");
439// );
440// ASSERT_TRUE(result);
441// ASSERT_EQ(24, result->GetValueAsString().size()) << result->GetValueAsString();
442//
443// ASSERT_NO_THROW(
444// result = ctx.ExecStr("\\temp\\module_test::__file__");
445// );
446// ASSERT_TRUE(result);
447// ASSERT_TRUE(result->GetValueAsString().find("temp/module_test.src") != std::string::npos) << result->GetValueAsString();
448//
449//
450// ASSERT_NO_THROW(
451// result = ctx.ExecStr("\\temp\\module_test::__main__");
452// );
453// ASSERT_TRUE(result);
454// ASSERT_STREQ("0", result->GetValueAsString().c_str()) << result->GetValueAsString();
455//}
456
457#endif // UNITTEST
Definition nlc.h:59
std::shared_ptr< Term > TermPtr
Definition variable.h:33
std::shared_ptr< RunTime > RuntimePtr
Definition types.h:242
std::string include
Definition runtime.h:136
std::string bytecode
Definition runtime.h:138
std::string name
Definition runtime.h:135
std::string source
Definition runtime.h:137