NewLang Project
Yet another programm language
Loading...
Searching...
No Matches
class_test.cpp
Go to the documentation of this file.
1#ifdef BUILD_UNITTEST
2
3#include "warning_push.h"
4
5
6#include "clang/Tooling/Tooling.h"
7#include "clang/Tooling/CommonOptionsParser.h"
8
9#include <gtest/gtest.h>
10#include "warning_pop.h"
11
12#include "runtime.h"
13
14
15using namespace newlang;
16
17static llvm::cl::OptionCategory MyToolCategory("my-tool options");
18
19//TEST(Compiler, EvalExample) {
20//
21// TermPtr p;
22// Parser parser(p);
23// parser.Parse("newlang(cpp);\n#Simple example\n{%printf(\"Hello world!\");%}");
24// ASSERT_EQ(2, p->BlockCode().size());
25//
26// TermPtr op = p->BlockCode()[0];
27// ASSERT_TRUE(op);
28//
29// ASSERT_EQ(TermID::NAME, op->getTermID());
30// ASSERT_TRUE(op->isCall());
31// ASSERT_STREQ("newlang", op->getText().c_str());
32// ASSERT_EQ(1, op->size());
33// ASSERT_STREQ("cpp", (*op)[0].second->getText().c_str());
34//
35// op = p->BlockCode()[1];
36// ASSERT_EQ(TermID::EMBED, op->getTermID());
37// ASSERT_STREQ("printf(\"Hello world!\");", op->getText().c_str());
38// ASSERT_EQ(0, op->size());
39//}
40//
41//
42
43
44class MyPrinter : public clang::ast_matchers::MatchFinder::MatchCallback {
45public:
46
47 clang::MangleContext *m_mangle_ctx;
48 std::vector<std::string > mangle_list;
49
50 MyPrinter() : m_mangle_ctx(nullptr) {
51 }
52
53 ~MyPrinter() {
54 if (m_mangle_ctx) {
55 delete m_mangle_ctx;
56 m_mangle_ctx = nullptr;
57 }
58 }
59
60 virtual void run(const clang::ast_matchers::MatchFinder::MatchResult &Result) {
61
62 clang::ASTContext *ctx = Result.Context;
63 ASSERT(ctx);
64
65 if (!m_mangle_ctx) {
66 m_mangle_ctx = ctx->createMangleContext();
67 }
68 ASSERT(m_mangle_ctx);
69
70
71 std::string name;
72 llvm::raw_string_ostream raw(name);
73
74 // llvm::outs() << Result.Nodes.getMap().size() << " nodes matched\n";
75 // Context->DumpRecordLayout()
76
77
78 if (const auto decl = Result.Nodes.getNodeAs<clang::Decl>("decl")) {
79 name = decl->getDeclKindName();
80 if (name.compare("LinkageSpec") == 0
81 || name.compare("Namespace") == 0
82 || name.compare("ParmVar") == 0
83 || name.compare("Empty") == 0
84 || name.compare("TranslationUnit") == 0
85 || name.compare("Typedef") == 0
86 ) {
87 return;
88 }
89 name.clear();
90 }
91
92 if (const auto decl = Result.Nodes.getNodeAs<clang::CXXRecordDecl>("decl")) {
93 // Ignore
94 // Определение класса, ссылка на класс (предварительное определение), в том числе скрытая
95 if (decl->isReferenced() || decl->isImplicit() || decl->isClass()) {
96 return;
97 }
98 }
99
100 if (const auto decl = Result.Nodes.getNodeAs<clang::CXXDestructorDecl>("decl")) {
101 // decl->dump();
102 // //
103 // // ASSERT(mangler->shouldMangleDeclName(decl));
104 // // mangler->mangleCXXDtorThunk(clang::GlobalDecl(decl), raw);
105 // // LOG_DEBUG("CXXDestructorDecl %s", name.c_str());
106 // //
107 // mangle_list.push_back(decl->getNameAsString());
108 } else if (const auto decl = Result.Nodes.getNodeAs<clang::CXXConstructorDecl>("decl")) {
109 // decl->dump();
110 //
111 // mangle_list.push_back(decl->getNameAsString());
112 //
113 // //
114 // // ASSERT(mangler->shouldMangleDeclName(decl));
115 // // mangler->mangleCtorBlock(decl, raw);
116 // // LOG_DEBUG("CXXConstructorDecl %s", name.c_str());
117 // //
118 } else if (const auto decl = Result.Nodes.getNodeAs<clang::FunctionDecl>("decl")) {
119 if (m_mangle_ctx->shouldMangleCXXName(decl)) {
120 m_mangle_ctx->mangleCXXName(decl, raw);
121
122 if (name.compare("_Znwm") == 0
123 || name.compare("_Znam") == 0
124 || name.compare("_ZdlPv") == 0
125 || name.compare("_ZdaPv") == 0
126 || name.rfind("SEOS_") != std::string::npos
127 || name.rfind("SEOS0_") != std::string::npos //name::ns_class::operator=(name::ns_class&&)
128 || name.rfind("SERKS_") != std::string::npos //class_body::operator=(class_body const&)
129 || name.rfind("SERKS0_") != std::string::npos //name::ns_class::operator=(name::ns_class const&)
130 ) {
131 return;
132 }
133 } else {
134 name = decl->getNameAsString();
135 }
136 // LOG_DEBUG("FunctionDecl %s", name.c_str());
137 mangle_list.push_back(name);
138
139 } else if (const auto decl = Result.Nodes.getNodeAs<clang::VarDecl>("decl")) {
140 if (m_mangle_ctx->shouldMangleCXXName(decl)) {
141 m_mangle_ctx->mangleCXXName(decl, raw);
142 } else {
143 name = decl->getNameAsString();
144 }
145 // LOG_DEBUG("%s", decl->getNameAsString().c_str());
146 mangle_list.push_back(name);
147
148 } else if (const auto decl = Result.Nodes.getNodeAs<clang::FieldDecl>("decl")) {
149 if (m_mangle_ctx->shouldMangleCXXName(decl)) {
150 m_mangle_ctx->mangleCXXName(decl, raw);
151 } else {
152 name = decl->getNameAsString();
153 }
154 // LOG_DEBUG("FieldDecl %s", name.c_str());
155 mangle_list.push_back(name);
156
157 } else if (const auto decl = Result.Nodes.getNodeAs<clang::CXXRecordDecl>("decl")) {
158
159 decl->dump();
160 LOG_RUNTIME("CXXRecordDecl");
161
162 } else if (const auto decl = Result.Nodes.getNodeAs<clang::Decl>("decl")) {
163
164 // decl->dump();
165 // LOG_RUNTIME("DeclKindName: %s", decl->getDeclKindName());
166
167 } else {
168 for (const auto &elem : Result.Nodes.getMap()) {
169
170 LOG_DEBUG("%s", elem.first.c_str());
171 }
172 LOG_RUNTIME("ELSE");
173 }
174 }
175};
176
177
178const char * func_text = \
179 "int func(int arg, char, signed char, unsigned char);\n"
180 "int func(signed int arg, unsigned int arg2, signed short int arg3, unsigned short int arg4);\n"
181 "int func(const signed int arg, const unsigned int arg2);\n"
182 "int func(int &arg, int &&arg2, int *arg3); //, int **arg4, int **arg5, int ****arg6 \n"
183 "int func(const int &arg, const int &&arg2, const int *arg3); //, const int **arg4, const int **arg5, const int ****arg6 \n"
184 "void func(int arg, double arg2);\n"
185 "extern \"C\" int printf(const char * format, ...);\n"
186 "const int value_const=0;\n"
187 "namespace n { const int value_const=0; };\n"
188 "int value_value;\n"
189 "extern \"C\" int value_c;\n"
190 "namespace n { int value; };\n"
191 "class header_only;\n"
192 "class class_body{\n"
193 " int field;\n"
194 " class_body(){};\n"
195 " virtual ~class_body(){};\n"
196 " void method_header();\n"
197 " void method_body(){};\n"
198 " static header_only * static_call(header_only *);"
199 "};\n"
200 "namespace name {\n"
201 "int func(int arg);\n"
202 "class ns_class {"
203 " void method();"
204 " virtual void method_v();"
205 " virtual void method_v2()=0;"
206 " static void method_static();"
207 "};"
208 "};\n";
209
210
211/*
212 * Импорт обычных и вирутальных
213 */
214
215std::vector <const char *> mangle_name = {
216 "_Z4funcicah",
217 "_Z4funcijst",
218 "_Z4funcij",
219 "_Z4funcRiOiPi", //_Z4funcRiOiPiPS1_S2_PPS2_
220 "_Z4funcRKiOS_PS_", //_Z4funcRKiOS_PS_PS2_S3_PPS3_
221 "_Z4funcid",
222 "printf",
223 "_ZL11value_const",
224 "_ZN1nL11value_constE",
225 "value_value",
226 "value_c",
227 "_ZN1n5valueE",
228 "_ZN10class_body5fieldE",
229 "_ZN10class_body13method_headerEv",
230 "_ZN10class_body11method_bodyEv",
231 "_ZN10class_body11static_callEP11header_only",
232 "_ZN4name4funcEi",
233 "_ZN4name8ns_class6methodEv",
234 "_ZN4name8ns_class8method_vEv",
235 "_ZN4name8ns_class9method_v2Ev",
236 "_ZN4name8ns_class13method_staticEv",
237};
238
239#define ATTR
240//_GLIBCXX_VISIBILITY(default)
241
242/* ::func(arg:Int32, arg:Int8, arg:Char, arg:Byte): Int32*/
243ATTR int func1(int arg, char c1, signed char c2, unsigned char c3) {
244
245 return arg;
246}
247
248/* ::func(arg:Int32, arg2:Dword, arg3:Int16, arg4:Word): Int32*/
249ATTR int func2(signed int arg, unsigned int arg2, signed short int arg3, unsigned short int arg4) {
250
251 return arg;
252}
253
254/* ::func(arg:&&Int32, arg2:&&&Int32, arg3:&Int32): Int32*/
255ATTR int func3(int &arg, int &&arg2, int *arg3) {
256
257 return arg;
258}
259
260/* ::func(arg:&&Int32^, arg2:&&&Int32^, arg3:&Int32^): Int32*/
261ATTR int func4(const int &arg, const int &&arg2, const int *arg3) {
262
263 return arg;
264}
265
266/* ::func(arg:Int32 arg2:Double): None*/
267ATTR void func5(signed long long int arg, double arg2) {
268}
269
270namespace ns {
271
272 double func6(signed long long int arg1, const unsigned short arg2) {
273 return arg1*arg2;
274 };
275
276 namespace ns {
277
278 float func7(unsigned long long int arg1, double arg2) {
279 return arg1 + arg2;
280 };
281
282 }
283 /* ns::value_const^: Int32*/
284 ATTR signed int value_const;
285
286 /* ::ns::value: Int32 */
287 ATTR int value;
288
289 /* ::ns::value_ptr: &* Int32 */
290 static ATTR int * value_ptr;
291}
292
293/* ::value_const: Int32 */
294ATTR int value_value;
295/* value_c: Int32 */
296extern "C" {
297
298 ATTR int value_c;
299}
300
301std::string toCXXProto(const TermPtr term) {
302
303 int i1 = ns::value_const;
304 int i2 = ns::value;
305
306 ASSERT(term);
307 ASSERT(isNativeName(term->m_text)); // %
308 // ASSERT(isStaticName(term->m_text)); // ::
309 ASSERT(!isFieldName(term->m_text)); // .
310 ASSERT(!isLocalName(term->m_text)); // $
311
312 ASSERT(term->m_type);
313 ObjType res_type = RunTime::BaseTypeFromString(nullptr, term->m_type->m_text);
314
315 std::string cpp_prototype;
316
317 // Real name
318 std::string name = &term->m_text[1];
319 std::string suffix;
320 bool is_static = (isStaticName(name) && !term->isCall());
321 bool is_global = (isGlobalScope(name) && !term->isCall());
322
323 if (isStaticName(name)) {
324 if (isGlobalScope(name)) {
325 name = name.substr(2);
326 }
327 ASSERT(!isGlobalScope(name));
328 while (isStaticName(name)) {
329 cpp_prototype += "namespace ";
330 cpp_prototype += name.substr(0, name.find("::"));
331 cpp_prototype += " { ";
332 suffix += "; }";
333 name = name.substr(name.find("::") + 2);
334 }
335 }
336
337 if (is_static && !is_global) {
338 cpp_prototype += "static ";
339 }
340
341 cpp_prototype += toCXXType(res_type, false);
342 cpp_prototype += " ";
343
344 if (term->m_type->m_ref) {
345 cpp_prototype += toCXXRef(term->m_type->m_ref->m_text);
346 cpp_prototype += " ";
347 }
348
349 ASSERT(!name.empty());
350 cpp_prototype += name;
351
352 if (term->isCall()) {
353 // Функция
354 cpp_prototype += "(";
355 for (int i = 0; i < term->size(); i++) {
356 if (i) {
357 cpp_prototype += ", ";
358 }
359 TermPtr arg = term->at(i).second;
360
361 if (!arg->m_type) {
362 LOG_RUNTIME("Type arg %d not defined '%s'", i, term->toString().c_str());
363 }
364
365 // LOG_DEBUG("%s", arg->m_type_name.c_str());
366 ObjType arg_type = RunTime::BaseTypeFromString(nullptr, arg->m_type->m_text);
367 if (arg->m_type->m_ref) {
368 cpp_prototype += " ";
369 cpp_prototype += toCXXRef(arg->GetType()->m_ref->m_text);
370 }
371 if (arg->m_type->m_is_const) {
372 cpp_prototype += "const ";
373 }
374 cpp_prototype += toCXXType(arg_type, false);
375 }
376 cpp_prototype += ")";
377
378 if (term->m_is_const) {
379 cpp_prototype.insert(0, " const");
380 }
381 }
382
383 if (term->m_is_const && !term->isCall()) {
384 if (isStringChar(res_type)) {
385 cpp_prototype += "=\"\"";
386 } else if (isStringWide(res_type)) {
387 cpp_prototype += "=L\"\"";
388 } else if (isArithmeticType(res_type)) {
389 cpp_prototype += "=0";
390 } else {
391 cpp_prototype += "=nullptr";
392 }
393 }
394
395 if (term->m_is_const) {
396 cpp_prototype += "const ";
397 }
398
399 cpp_prototype += suffix;
400 cpp_prototype += ";";
401
402 return cpp_prototype;
403}
404
405std::string toCXXProto(std::string name) {
406 std::string result;
407 name += ":= _";
408 TermPtr term = Parser::ParseString(name, nullptr);
409
410 return toCXXProto(term->Left());
411}
412
413/*
414 * void foo() {} // _Z3foov == _Z3foov
415 * void foo(int a){} // _Z3fooi == _Z3fooi
416 * double foo(double d){return 0;} // _Z3food == _Z3food
417 * void foo(int a, double d) {} // _Z3fooid == _Z3fooid
418 * namespace test {
419 * void foo(int a) {} // _ZN4test3fooEi == _ZN4test3fooEi
420 * double foo(double d) {return 0;} //_ZN4test3fooEd == _ZN4test3fooEd
421 * }
422 *
423 *
424Posted on 25. October 2019 by JP Lehr
425Name mangling in C++ with Clang and GCC
426
427I recently came across the question whether it is possible to use lists of mangled function names (generated with a Clang-based tool) in a GCC compiler plugin. I am aware that name mangling is compiler dependent and not standardized, yet I had hopes that this would be something I can achieve.
428
429I started with a quick web search. That, however, did not lead to satisfying answers, as I was still unsure whether it could actually work. Most of the answers I found were about the status when GCC 5 came out. Now, I am working with GCC 8 and things may change.
430
431So, I continued by implementing very basic test cases to start this off experimentally, i.e., to get an idea on whether more reading about all this is worth my time. Codes were as simple as the one shown below. The first name in the comment is the GCC mangled name (g++ 8.3) and the second name is the Clang mangled name (clang++ 9.0).
432
433void foo() {} // _Z3foov == _Z3foov
434void foo(int a){} // _Z3fooi == _Z3fooi
435double foo(double d){return 0;} // _Z3food == _Z3food
436void foo(int a, double d) {} // _Z3fooid == _Z3fooid
437namespace test {
438 void foo(int a) {} // _ZN4test3fooEi == _ZN4test3fooEi
439 double foo(double d) {return 0;} //_ZN4test3fooEd == _ZN4test3fooEd
440}
441
442 * So, at least given this small set of samples, there do not seem to be differences.
443 * I did similar tiny-scale experiments for classes and templates. All of them were simple enough to not discover differences.
444 * Eventually, I applied both compilers to a basic C++ implementation of the game of life (sources) and filtered the object code
445 * to get a list of all the function names in the resulting binary.
446 * I compiled at optimization level 0 to let the compiler not do inlining or other optimizations.
447 * I’m sure listing all functions in an object can be done much easier (e.g., using nm),
448 * but this is what I did (accordingly for a version of the code compiled with g++):
449 *
450 * objdump -d clang++90.GoL | grep ">:" | awk '{ print $2 }' | sed -e "s/://" | uniq | sort > clang++90_names
451 *
452 * Inspecting both lists of generated function names, I found differences. In particular, in the mangled name
453 * of the constructor of the GameOfLife class.
454 *
455 * class GameOfLife {
456 * public:
457 * GameOfLife(int numX, int numY) : dimX(numX),
458 * dimY(numY),
459 * gridA(dimXdimY,
460 * gridB(dimXdimY){}
461 * // other members are omitted
462 * };
463 *
464 * The constructor is mangled into _ZN10GameOfLifeC1Eii by GCC and into _ZN10GameOfLifeC2Eii by Clang.
465 * The difference is the C1 vs. the C2 in the name.
466 *
467 * <ctor-dtor-name> ::= C1 # complete object constructor
468 ::= C2 # base object constructor
469 ::= C3 # complete object allocating constructor
470 ::= D0 # deleting destructor
471 ::= D1 # complete object destructor
472 ::= D2 # base object destructor
473 *
474
475 First of all, choose different names for different things.
476
477 Second, the non-static member function pointer should be declared as:
478
479 void (classA::*memfun)(void); //note the syntax
480
481 then the assignment should be as:
482
483 memfun = &classA::function_a; //note &, and note the syntax on both sides.
484
485 and you call this as:
486
487 classA instance;
488 (instance.*memfun)();
489
490 That is what you do in C++03.
491
492 However, in C++11, you can use std::function as well. Here is how you do it:
493
494 std::function<void(classA*)> memfun(&classA::function_a);
495
496 and you call this as:
497
498 classA instance;
499 memfun(&instance);
500
501 *
502 */
503
504std::vector<std::string> GetMangledNames(const std::string input_source) {
505
506 clang::CompilerInstance compilerInstance;
507
508 constexpr int COUNT = 3;
509 int argc = COUNT;
510 const char *argv[COUNT] = {"", "clang_mangled_names.cpp", "--"};
511
512 auto OptionsParser = clang::tooling::CommonOptionsParser::create(argc, argv, MyToolCategory, llvm::cl::OneOrMore);
513 if (!OptionsParser) {
514 LOG_RUNTIME("Fail create OptionsParser!");
515 }
516
517 clang::tooling::ClangTool Tool(OptionsParser->getCompilations(), OptionsParser->getSourcePathList());
518
519 Tool.mapVirtualFile("clang_mangled_names.cpp", clang::StringRef(input_source));
520
521 MyPrinter Printer;
522 auto functionMatcher = clang::ast_matchers::decl(clang::ast_matchers::anything()).bind("decl");
523
524 clang::ast_matchers::MatchFinder Finder;
525 Finder.addMatcher(functionMatcher, &Printer);
526
527 if (0 != Tool.run(clang::tooling::newFrontendActionFactory(&Finder).get())) {
528
529 LOG_RUNTIME("Fail run FrontendAction!");
530 }
531
532 // if (Printer.mangle_list.size() != names.size()) {
533 // LOG_RUNTIME("Fail matching result!");
534 // }
535 return Printer.mangle_list;
536}
537
538std::string GetMangledString(const std::string_view source) {
539 std::vector<std::string> list = GetMangledNames(toCXXProto(std::string(source)));
540 if (list.size() != 1) {
541 LOG_RUNTIME("Source '%s' not a single mangled name!", source.begin());
542 }
543 return list[0];
544}
545
546TEST(Class, MangledSimple) {
547
548 std::string name;
549 std::string mandled;
550
551 LLVMLoadLibraryPermanently(nullptr);
552
553 EXPECT_TRUE(LLVMSearchForAddressOfSymbol("printf"));
554 EXPECT_TRUE(LLVMSearchForAddressOfSymbol("fopen"));
555
556 ASSERT_STREQ("signed int value_c;", toCXXProto("%value_c:Int32").c_str());
557 ASSERT_NO_THROW(mandled = GetMangledString("%value_c:Int32"));
558 ASSERT_STREQ("value_c", mandled.c_str());
559 ASSERT_TRUE(LLVMSearchForAddressOfSymbol(mandled.c_str())) << mandled;
560
561
562 ASSERT_STREQ("signed int func1(signed int, char, signed char, unsigned char);",
563 toCXXProto("%::func1(arg:Int32, arg:Int8, arg:Char, arg:Byte): Int32").c_str());
564 ASSERT_NO_THROW(mandled = GetMangledString("%::func1(arg:Int32, arg:Int8, arg:Char, arg:Byte): Int32"));
565 ASSERT_STREQ("_Z5func1icah", mandled.c_str());
566 ASSERT_TRUE(LLVMSearchForAddressOfSymbol(mandled.c_str())) << mandled;
567
568
569 ASSERT_STREQ("signed int func2(signed int, unsigned int, signed short, unsigned short);",
570 toCXXProto("%::func2(arg:Int32, arg2:DWord, arg3:Int16, arg4:Word): Int32").c_str());
571 ASSERT_NO_THROW(mandled = GetMangledString("%::func2(arg:Int32, arg2:DWord, arg3:Int16, arg4:Word): Int32"));
572 ASSERT_STREQ("_Z5func2ijst", mandled.c_str());
573 ASSERT_TRUE(LLVMSearchForAddressOfSymbol(mandled.c_str())) << mandled;
574
575
576 ASSERT_STREQ("void func5(signed long long int, double);",
577 toCXXProto("%::func5(arg:Int64, arg2:Double):None").c_str());
578 ASSERT_NO_THROW(mandled = GetMangledString("%::func5(arg:Int64, arg2:Double):None"));
579 ASSERT_STREQ("_Z5func5xd", mandled.c_str());
580 ASSERT_TRUE(LLVMSearchForAddressOfSymbol(mandled.c_str())) << mandled;
581
582
583 ASSERT_STREQ("namespace ns { double func6(signed long long int, const unsigned short); };",
584 toCXXProto("%::ns::func6(arg:Int64, arg2: Word^):Double").c_str());
585 ASSERT_NO_THROW(mandled = GetMangledString("%::ns::func6(arg:Int64, arg2:Word^):Double"));
586 ASSERT_STREQ("_ZN2ns5func6Ext", mandled.c_str());
587 ASSERT_TRUE(LLVMSearchForAddressOfSymbol(mandled.c_str())) << mandled;
588
589
590 ASSERT_STREQ("namespace ns { namespace ns { float func7(unsigned long long int, double); }; };",
591 toCXXProto("%ns::ns::func7(arg:DWord64, arg2:Double):Single").c_str());
592 ASSERT_NO_THROW(mandled = GetMangledString("%ns::ns::func7(arg:DWord64, arg2:Double):Single"));
593 ASSERT_STREQ("_ZN2ns2ns5func7Eyd", mandled.c_str());
594 ASSERT_TRUE(LLVMSearchForAddressOfSymbol(mandled.c_str())) << mandled;
595
596
597 ASSERT_STREQ("namespace ns { signed int value_const; };", toCXXProto("%::ns::value_const:Int32").c_str());
598 ASSERT_NO_THROW(mandled = GetMangledString("%::ns::value_const:Int32"));
599 ASSERT_STREQ("_ZN2ns11value_constE", mandled.c_str());
600 //"_ZN2nsL11value_constE"
601 ASSERT_TRUE(LLVMSearchForAddressOfSymbol(mandled.c_str())) << mandled;
602
603
604 ASSERT_STREQ("signed int value_value;", toCXXProto("%value_value:Int32").c_str());
605 ASSERT_NO_THROW(mandled = GetMangledString("%value_value:Int32"));
606 ASSERT_STREQ("value_value", mandled.c_str());
607 ASSERT_TRUE(LLVMSearchForAddressOfSymbol(mandled.c_str())) << mandled;
608
609 name = "%ns::value_ptr: &* Int32";
610 ASSERT_STREQ("namespace ns { static signed int * value_ptr; };", toCXXProto(name).c_str());
611 ASSERT_NO_THROW(mandled = GetMangledString(name)) << name;
612 ASSERT_STREQ("_ZN2nsL9value_ptrE", mandled.c_str());
613 //_ZN2ns9value_ptrE
614 // Статической переменной нет в таблице символов!!!!
615 ASSERT_FALSE(LLVMSearchForAddressOfSymbol(mandled.c_str())) << mandled;
616
617
618 // ASSERT_NO_THROW(list = GetMangledNames("%::class_body.field:Int32"));
619 // ASSERT_EQ(1, list.size()) << Dump(list);
620 // ASSERT_STREQ("", list[0].c_str()) << list[0];
621 //
622 // ASSERT_NO_THROW(list = GetMangledNames("%::class_body.method():Int32"));
623 // ASSERT_EQ(1, list.size()) << Dump(list);
624 // ASSERT_STREQ("", list[0].c_str()) << list[0];
625
626
627}
628
629struct class_body {
630 int field;
631 static char static_field;
632
633 class_body() {
634 }
635
636 class_body(int, int *) {
637 }
638
639 virtual ~class_body() {
640 }
641
642 void method_body() {
643 }
644
645 int method_body(int arg) {
646 return arg;
647 }
648
649 double method_body(double arg) {
650 return arg;
651 }
652
653 int method_body2(int arg) {
654 return arg * 2;
655 }
656
657 virtual double method_virt() {
658 return 3.14;
659 }
660
661 static float method_static() {
662 return 3.1415;
663 }
664};
665
666/*
667 * У нативных классов можно импортировть только публичные не статические <не виртуальные?????> методы!!!
668 * Прегруженные методы пока под вопросом?
669 * Поля использовать нельзя из-за их определения как смещения в объекте, а не адресом в памяти, как тело функции.
670 * Статические поля и методы использовать нельзя из-за отсутсвия на них ссылки в глобальной таблице имен.
671 * У виртуальных функций есть адрес в глобальной таблице имен, но как их вызывать, пока не понятно.
672 * Причем обычные методы, если на них нет ссылки (не используются), могут удаляться из приложения линкером.
673 */
674
675const char * cls = ""
676 "class class_body {"
677 "public:"
678 " int field;"
679 ""
680 "static char static_field;"
681 ""
682 " class_body();"
683 ""
684 " class_body(int, int *);"
685 ""
686 " virtual ~class_body();"
687 ""
688 " void method_body();"
689 ""
690 " int method_body(int arg);"
691 ""
692 " double method_body(double arg);"
693 ""
694 " int method_body2(int arg);"
695 ""
696 " virtual double method_virt();"
697 ""
698 " static float method_static();"
699 "};"
700 "";
701
702std::string FindMandledField(std::string source, std::vector<std::string> &list) {
703
704 source += ":= _";
705 TermPtr term = Parser::ParseString(source, nullptr);
706 ASSERT(term->m_left);
707
708 std::vector<std::string> names = GetMangledNames(toCXXProto(term->m_left));
709 if (names.size() != 1) {
710 LOG_RUNTIME("Source '%s' not a single mangled name!", source.c_str());
711 }
712 std::string mangled = names[0];
713
714 std::string search = term->m_left->m_text.substr(1);
715 if (isGlobalScope(search)) {
716 search = search.substr(2);
717 }
718 ASSERT(!isStaticName(search));
719
720 std::string arg_types("E");
721 if (term->m_left->isCall()) {
722 arg_types += mangled.substr(mangled.find(search) + search.size());
723 }
724
725 for (auto &elem : list) {
726 if (elem.find(search) != std::string::npos && (arg_types.empty() || elem.find(arg_types) != std::string::npos)) {
727 return elem;
728 }
729 }
730 LOG_RUNTIME("Filed '%s' (%s)(%s) not found!", term->m_left->m_text.c_str(), search.c_str(), arg_types.c_str());
731}
732
733template<typename OUT, typename IN>
734OUT ForceCast(IN in) {
735
736 union {
737 IN in;
738 OUT out;
739 }
740 u = {in};
741
742 return u.out;
743};
744
745char class_body::static_field = 0;
746
747TEST(Class, MangledClass) {
748
749 class_body data;
750 data.field = 0;
751 data.method_body();
752 data.method_body(0);
753 data.method_body(0.0);
754 data.method_body2(0);
755 data.method_static();
756
757 std::string name;
758 std::vector<std::string> list;
759
760 void *cast;
761 LLVMLoadLibraryPermanently(nullptr);
762
763 ASSERT_NO_THROW(list = GetMangledNames(cls));
764 ASSERT_EQ(8, list.size()) << Dump(list);
765
766 ASSERT_STREQ("void method_body();", toCXXProto("%method_body(): None").c_str());
767 ASSERT_NO_THROW(name = GetMangledString("%method_body(): None"));
768 ASSERT_STREQ("_Z11method_bodyv", name.c_str());
769 ASSERT_NO_THROW(name = FindMandledField("%method_body():None", list)) << Dump(list);
770 EXPECT_TRUE(LLVMSearchForAddressOfSymbol(name.c_str())) << name << "\n" << Dump(list);
771
772 ASSERT_STREQ("signed int method_body(signed int);", toCXXProto("%method_body(arg:Int32): Int32").c_str());
773 ASSERT_NO_THROW(name = GetMangledString("%method_body(arg:Int32): Int32"));
774 ASSERT_STREQ("_Z11method_bodyi", name.c_str());
775 ASSERT_NO_THROW(name = FindMandledField("%method_body(arg:Int32): Int32", list)) << Dump(list);
776 EXPECT_TRUE(LLVMSearchForAddressOfSymbol(name.c_str())) << name << "\n" << Dump(list);
777
778 ASSERT_STREQ("double method_body(double);", toCXXProto("%method_body(arg:Double): Double").c_str());
779 ASSERT_NO_THROW(name = GetMangledString("%method_body(arg:Double): Double"));
780 ASSERT_STREQ("_Z11method_bodyd", name.c_str());
781 ASSERT_NO_THROW(name = FindMandledField("%method_body(arg:Double): Double", list)) << Dump(list);
782 EXPECT_TRUE(LLVMSearchForAddressOfSymbol(name.c_str())) << name << "\n" << Dump(list);
783
784// cast = ForceCast<void *>(&class_body::method_body);
785// ASSERT_EQ(cast, LLVMSearchForAddressOfSymbol(name.c_str()));
786
787 ASSERT_STREQ("signed int method_body2(signed int);", toCXXProto("%method_body2(arg:Int32): Int32").c_str());
788 ASSERT_NO_THROW(name = GetMangledString("%method_body2(arg:Int32): Int32"));
789 ASSERT_STREQ("_Z12method_body2i", name.c_str());
790 ASSERT_NO_THROW(name = FindMandledField("%method_body2(arg:Int32): Int32", list)) << Dump(list);
791 EXPECT_TRUE(LLVMSearchForAddressOfSymbol(name.c_str())) << name << "\n" << Dump(list);
792
793 cast = ForceCast<void *>(&class_body::method_body2);
794 ASSERT_EQ(cast, LLVMSearchForAddressOfSymbol(name.c_str()));
795
796 ASSERT_STREQ("double method_virt();", toCXXProto("%method_virt(): Double").c_str());
797 ASSERT_NO_THROW(name = GetMangledString("%method_virt(): Double"));
798 ASSERT_STREQ("_Z11method_virtv", name.c_str());
799 ASSERT_NO_THROW(name = FindMandledField("%method_virt(): Double", list)) << Dump(list);
800 EXPECT_TRUE(LLVMSearchForAddressOfSymbol(name.c_str())) << name << "\n" << Dump(list);
801
802// cast = ForceCast<void *>(&class_body::method_virt);
803// ASSERT_EQ(cast, LLVMSearchForAddressOfSymbol(name.c_str()));
804
805 // ASSERT_STREQ("float method_static();", toCXXProto("%::method_static(): Single").c_str());
806 // ASSERT_NO_THROW(name = GetMangledString("%::method_static(): Single"));
807 // ASSERT_STREQ("_Z13method_staticv", name.c_str());
808 // ASSERT_NO_THROW(name = FindMandledField("%::method_static(): Single", list)) << Dump(list);
809 // EXPECT_TRUE(LLVMSearchForAddressOfSymbol(name.c_str())) << name << "\n" << Dump(list);
810
811 // ASSERT_STREQ("signed int field;", toCXXProto("%field: Int32").c_str());
812 // ASSERT_NO_THROW(name = GetMangledString("%field: Int32"));
813 // ASSERT_STREQ("field", name.c_str());
814 // ASSERT_NO_THROW(name = FindMandledField("%field: Int32", list)) << Dump(list);
815 // EXPECT_TRUE(LLVMSearchForAddressOfSymbol(name.c_str())) << name << "\n" << Dump(list);
816 // EXPECT_TRUE(dlsym(nullptr, name.c_str()));
817
818
819 ASSERT_STREQ("signed int static_field;", toCXXProto("%::static_field: Int32").c_str());
820 ASSERT_NO_THROW(name = GetMangledString("%::static_field: Int32"));
821 ASSERT_STREQ("static_field", name.c_str());
822 ASSERT_NO_THROW(name = FindMandledField("%::static_field: Int32", list)) << Dump(list);
823 EXPECT_TRUE(LLVMSearchForAddressOfSymbol(name.c_str())) << name << "\n" << Dump(list);
824
825}
826
827//
828//std::vector<std::string> toMangledName(std::vector<std::string> names) {
829//
830// std::string input_source;
831// for (auto &elem : names) {
832// input_source += toCXXProto(elem);
833// input_source += "\n";
834// }
835//
836// clang::CompilerInstance compilerInstance;
837//
838// constexpr int COUNT = 3;
839// int argc = COUNT;
840// const char *argv[COUNT] = {"", "fake.cpp", "--"};
841//
842// auto OptionsParser = clang::tooling::CommonOptionsParser::create(argc, argv, MyToolCategory, llvm::cl::OneOrMore);
843// if (!OptionsParser) {
844// LOG_RUNTIME("Fail create OptionsParser!");
845// }
846//
847// clang::tooling::ClangTool Tool(OptionsParser->getCompilations(), OptionsParser->getSourcePathList());
848//
849// Tool.mapVirtualFile("fake.cpp", clang::StringRef(input_source));
850//
851// MyPrinter Printer;
852// auto functionMatcher = clang::ast_matchers::decl(clang::ast_matchers::anything()).bind("decl");
853//
854// clang::ast_matchers::MatchFinder Finder;
855// Finder.addMatcher(functionMatcher, &Printer);
856//
857// if (0 != Tool.run(clang::tooling::newFrontendActionFactory(&Finder).get())) {
858// LOG_RUNTIME("Fail run FrontendAction!");
859// }
860//
861// if (Printer.mangle_list.size() != names.size()) {
862// LOG_RUNTIME("Fail matching result!");
863// }
864// return Printer.mangle_list;
865//}
866//
867//inline std::string toMangledName(std::string name) {
868// std::vector<std::string> names({name});
869// return toMangledName(names)[0];
870//}
871//
872//TEST(Class, MangleName) {
873//
874// EXPECT_STREQ("newlang_min", MangleName("мин").c_str()) << MangleName("мин");
875// EXPECT_STREQ("newlang_maks", MangleName("макс").c_str()) << MangleName("макс");
876//
877//
878// clang::CompilerInstance compilerInstance;
879//
880// constexpr int COUNT = 3;
881// int argc = COUNT;
882// const char *argv[COUNT] = {"", "fake.cpp", "--"};
883//
885// auto OptionsParser = clang::tooling::CommonOptionsParser::create(argc, argv, MyToolCategory, llvm::cl::OneOrMore);
886// ASSERT_TRUE(!!OptionsParser);
887//
888// clang::tooling::ClangTool Tool(OptionsParser->getCompilations(), OptionsParser->getSourcePathList());
889//
890// Tool.mapVirtualFile("fake.cpp", clang::StringRef(func_text));
891//
892// MyPrinter Printer;
893// auto functionMatcher = clang::ast_matchers::decl(clang::ast_matchers::anything()).bind("decl");
894//
895// clang::ast_matchers::MatchFinder Finder;
896// Finder.addMatcher(functionMatcher, &Printer);
897//
898// ASSERT_EQ(0, Tool.run(clang::tooling::newFrontendActionFactory(&Finder).get()));
899//
900// for (int i = 0; i < std::min(Printer.mangle_list.size(), mangle_name.size()); i++) {
901// EXPECT_STREQ(mangle_name[i], Printer.mangle_list[i].c_str()) << i;
902// }
903// ASSERT_EQ(Printer.mangle_list.size(), mangle_name.size());
904//
905//}
906//
908// * C++ NewLang
909// * * &*
910// * & &
911// * && &&
912// * const * &*^
913// * const & &^
914// * const && &&^
915// * ** &? ????????????????????????
916// * const ** &?^ ????????????????????????
917// */
918//
919//struct ImportType {
920// void * ptr;
921// const char * name;
922// const char * mangle;
923// const char * proto;
924//};
925//std::vector <ImportType> import_names = {
926// {(void *) &value_c, "value_c:Int32", "value_c", "signed int value_c;"},
927// {(void *) &func1, "::func1(arg:Int32, arg:Int8, arg:Char, arg:Byte): Int32", "_Z5func1icah", "signed int func1(signed int, char, signed char, unsigned char);"},
928// {(void *) &func2, "::func2(arg:Int32, arg2:DWord, arg3:Int16, arg4:Word): Int32", "_Z5func2ijst", "signed int func2(signed int, unsigned int, signed short, unsigned short);"},
929// {(void *) &func3, "::func3(arg:&&Int32, arg2:&&&Int32, arg3:&Int32): Int32", "_Z5func3RiOiPi", "signed int func3(signed int &, signed int &&, signed int *);"},
930// {(void *) &func4, "::func4(arg:&&Int32^, arg2:&&&Int32^, arg3:&Int32^): Int32", "_Z5func4RKiOS_PS_", "signed int func4(const signed int &, const signed int &&, const signed int *);"},
931// {(void *) &func5, "::func5(arg:Int64, arg2:Double):None", "_Z5func5xd", "void func5(signed long long int, double);"}, //
932// // {(void *) &n::value_const, "::value_const: Int32^", "_ZN1nL11value_constE", ""}, //_ZN1nL11value_constE value_const
933// {(void *) &value_value, "value_value:Int32", "value_value", "signed int value_value;"},
934// // {(void *) &n::value, "::n::value:Int32", "_ZN1n5valueE", ""},
935// // {nullptr, "::class_body.field:Int32", "", ""},
936// // {nullptr, "::class_body::class_body()", "", ""},
937// // {nullptr, "::class_body.method_body()", "", ""},
938// // {(void *) &class_body::method_static, "::class_body::method_static():None", "", ""},
939//
940//};
941//
942//TEST(Class, ParserNS) {
943// // ASSERT_FALSE(LLVMSearchForAddressOfSymbol("value_c"));
944// ASSERT_EQ(0, LLVMLoadLibraryPermanently(nullptr));
945// ASSERT_TRUE(LLVMSearchForAddressOfSymbol("value_c"));
946// ASSERT_TRUE(LLVMSearchForAddressOfSymbol("_Z5func5xd"));
947// ASSERT_TRUE(LLVMSearchForAddressOfSymbol("_ZN1n5valueE"));
948//
949//
950// for (int i = 0; i < import_names.size(); i++) {
951// EXPECT_TRUE(LLVMSearchForAddressOfSymbol(import_names[i].mangle)) << "i: " << i << " -> '" << import_names[i].mangle << "'";
952// EXPECT_STREQ(toCXXProto(import_names[i].name).c_str(), import_names[i].proto) << import_names[i].name;
953// EXPECT_STREQ(toMangledName(import_names[i].name).c_str(), import_names[i].mangle) << import_names[i].name;
954// }
955//}
956
957void test_void_func() {
958}
959
960const int test_void_val = 0;
961
962TEST(Class, Symbols) {
963
964 auto rt = RunTime::Init();
965
966
967 EXPECT_TRUE(LLVMSearchForAddressOfSymbol("printf"));
968 EXPECT_TRUE(LLVMSearchForAddressOfSymbol("fopen"));
969
970 EXPECT_FALSE(LLVMSearchForAddressOfSymbol("test_void_func"));
971 EXPECT_FALSE(LLVMSearchForAddressOfSymbol("test_void_val"));
972
973 LLVMAddSymbol("test_void_func", (void *) &test_void_func);
974 LLVMAddSymbol("test_void_val", (void *) &test_void_val);
975
976 EXPECT_TRUE(LLVMSearchForAddressOfSymbol("test_void_func"));
977 EXPECT_TRUE(LLVMSearchForAddressOfSymbol("test_void_val"));
978
979 EXPECT_EQ(&test_void_func, LLVMSearchForAddressOfSymbol("test_void_func"));
980 EXPECT_EQ(&test_void_val, LLVMSearchForAddressOfSymbol("test_void_val"));
981}
982
983
984
985//#define ASSERT_STRSTART(base, val) ASSERT_TRUE(str_cmp_strart(base, val))<<" \""<<base<<"\"\n \""<<val<<"\""
986//#define EXPECT_STRSTART(base, val) EXPECT_TRUE(str_cmp_strart(base, val))<<" \""<<base<<"\"\n \""<<val<<"\""
987//
988//bool str_cmp_strart(const char *base_str, const char *cmp_str) {
989// std::string base(base_str);
990// std::string cmp(cmp_str);
991// for (size_t i = 0; i < base.size() && i < cmp.size(); i++) {
992// if(base[i] != cmp[i]) {
993//
994// return false;
995// }
996// }
997// return base.size() <= cmp.size();
998//}
999//
1011//
1225//
1277//
1278//TEST(Compiler, DISABLED_Function) {
1279//
1280// const char *func_text =
1281// "func_sum(arg1, arg2) :- {$arg1 + $arg2;};\n"
1282// "func_call(arg1, arg2) :- {func_sum($arg1, $arg2);};";
1283//
1284// TermPtr funcs;
1285// Parser parser(funcs);
1286//
1287// parser.Parse(func_text);
1288// ASSERT_TRUE(funcs);
1289// ASSERT_EQ(TermID::BLOCK, funcs->getTermID());
1290// ASSERT_EQ(2, funcs->BlockCode().size());
1291//
1292// TermPtr func1 = funcs->BlockCode()[0];
1293//
1294// ASSERT_EQ(TermID::PURE_ONCE, func1->getTermID());
1295// ASSERT_TRUE(func1->Left());
1296// ASSERT_EQ(2, func1->Left()->size());
1297//
1298// ASSERT_TRUE(func1->Right());
1299// TermPtr body1 = func1->Right();
1300//
1301// // ASSERT_EQ(TermID::LOCAL, body1->getTermID());
1302// // ASSERT_TRUE(body1->Left());
1303// // ASSERT_TRUE(body1->Right());
1304// // ASSERT_STREQ(":=", body1->getText().c_str());
1305// // ASSERT_EQ(TermID::RESULT, body1->Left()->getTermID());
1306// // ASSERT_STREQ("$$", body1->Left()->getText().c_str());
1307// // ASSERT_EQ(TermID::OPERATOR, body1->Right()->getTermID());
1308//
1309// TermPtr op = body1->Right();
1310// // ASSERT_TRUE(op);
1311// // ASSERT_TRUE(op->Left());
1312// // ASSERT_TRUE(op->Right());
1313// // ASSERT_EQ(TermID::TERM, op->Left()->getTermID());
1314// // ASSERT_STREQ("+", op->getText().c_str());
1315// // ASSERT_STREQ("$arg1", op->Left()->getText().c_str());
1316// // ASSERT_STREQ("$arg2", op->Right()->getText().c_str());
1317//
1318//
1319// TermPtr func2 = funcs->BlockCode()[1];
1320//
1321// ASSERT_EQ(TermID::PURE_ONCE, func2->getTermID());
1322// ASSERT_TRUE(func2->Left());
1323// ASSERT_EQ(2, func2->Left()->size());
1324//
1325// // ASSERT_TRUE(func2->Right());
1326// // TermPtr body2 = func2->Right();
1327// // ASSERT_TRUE(body2);
1328// //
1329// // ASSERT_TRUE(body2->Left());
1330// // ASSERT_TRUE(body2->Right());
1331// // ASSERT_EQ(TermID::LOCAL, body2->getTermID());
1332// // ASSERT_STREQ(":=", body2->getText().c_str());
1333// // ASSERT_EQ(TermID::RESULT, body2->Left()->getTermID());
1334// // ASSERT_STREQ("$$", body2->Left()->getText().c_str());
1335// //
1336// // op = body2->Right();
1337// // ASSERT_TRUE(op);
1338// // ASSERT_FALSE(op->Left());
1339// // ASSERT_FALSE(op->Right());
1340// // ASSERT_EQ(TermID::CALL, op->getTermID());
1341// // ASSERT_STREQ("func_sum", op->getText().c_str());
1342// // ASSERT_EQ(2, op->size());
1343// // ASSERT_STREQ("$arg1", (*op)[0]->getText().c_str());
1344// // ASSERT_STREQ("$arg2", (*op)[1]->getText().c_str());
1345//
1346//
1347// std::ostringstream sstr;
1348// ASSERT_TRUE(Compiler::MakeCppFile(funcs, sstr)); // << sstr.str();
1349//
1350//
1351// std::filesystem::create_directories("temp");
1352// ASSERT_TRUE(std::filesystem::is_directory("temp"));
1353//
1354// std::ofstream file("temp/function_test.temp.cpp");
1355// file << sstr.str();
1356// file.close();
1357//}
1358//
1359//TEST(Compiler, DISABLED_FuncsTypes) {
1360//
1361// /*
1362// * - Проверка типов аргументов при вызове функций
1363// * - Проверка типов возвращаемых значений у функций
1364// */
1365//
1366// RuntimePtr opts = RunTime::Init();
1367// Context ctx(opts);
1368//
1369//#define FUNC_ARG "func_arg(arg1: Int8, arg2): Int8 := { $arg1+$arg2; };"
1370//#define FUNC_RES "func_res(arg1: Int8, arg2: Int32): Integer := { $arg2+=$arg1; };"
1371//
1372// TermPtr func;
1373// Parser parser(func);
1374//
1375// std::ostringstream sstr;
1376//
1377// // Не соответствие типа функции в операторе
1378// parser.Parse(FUNC_ARG FUNC_RES "\n$res:Int8 := func_arg(100, 100); $res += func_res(100, 100);");
1379// sstr.str("");
1380// ASSERT_THROW(Compiler::MakeCppFile(func, sstr, nullptr, &ctx), Return) << sstr.str();
1381//
1382// // Компилится без ошибок
1383// parser.Parse(FUNC_ARG "\nfunc_arg(Int8(100), 100);");
1384// sstr.str("");
1385// ASSERT_NO_THROW(Compiler::MakeCppFile(func, sstr, nullptr, &ctx)) << sstr.str();
1386//
1387// // Не соответствие типа первого аргумента
1388// parser.Parse(FUNC_ARG "\nfunc_arg(1000, 100);");
1389// sstr.str("");
1390// ASSERT_THROW(Compiler::MakeCppFile(func, sstr, nullptr, &ctx), Return) << sstr.str();
1391//
1392// // Не соответствие типа функции
1393// parser.Parse(FUNC_ARG FUNC_RES "\n$res:Int8 := func_res(100, 1000);");
1394// sstr.str("");
1395// ASSERT_THROW(Compiler::MakeCppFile(func, sstr, nullptr, &ctx), Return) << sstr.str();
1396//
1397// // Не соответствие типа функции в операторе
1398// parser.Parse(FUNC_ARG FUNC_RES "\n$res:Int8 := func_arg(100, 100); $res += func_res(100, 100);");
1399// sstr.str("");
1400// ASSERT_THROW(Compiler::MakeCppFile(func, sstr, nullptr, &ctx), Return) << sstr.str();
1401//
1402// // Нет типа у $res как в предыдщем случае
1403// parser.Parse(FUNC_ARG FUNC_RES "\n$res := func_arg(100, 100); $res += func_res(100, 100);");
1404// sstr.str("");
1405// ASSERT_NO_THROW(Compiler::MakeCppFile(func, sstr, nullptr, &ctx)) << sstr.str();
1406//
1407// // Тип есть, но делается каст возвращаемого типа у функции
1408// parser.Parse(FUNC_ARG FUNC_RES "\n$res: Int8 := func_arg(100, 100); $res += Int8(func_res(100, 100));");
1409// sstr.str("");
1410// ASSERT_NO_THROW(Compiler::MakeCppFile(func, sstr, nullptr, &ctx)) << sstr.str();
1411//
1412//
1413// std::filesystem::create_directories("temp");
1414// ASSERT_TRUE(std::filesystem::is_directory("temp"));
1415//
1416//
1417// std::ofstream file("temp/call_types.temp.cpp");
1418// file << sstr.str();
1419// file.close();
1420//
1421// std::string out;
1422// int exit_code;
1423// ASSERT_TRUE(Compiler::GccMakeModule("temp/call_types.temp.cpp",
1424// "temp/call_types.temp.nlm", nullptr,
1425// &out, &exit_code))
1426// << exit_code << " " << out;
1427//
1428// ASSERT_TRUE(ctx.m_runtime->LoadModule(ctx, "call_types.temp.nlm", false));
1429//
1430// // Переполнение байтовой переменной $res во время выполнения последнего оператора "+="
1431// // Obj args;
1432// // ASSERT_TRUE(ctx.m_runtime->m_modules["temp/call_types.temp.nlm"]);
1433// // ASSERT_NO_THROW(
1434// // ctx.m_runtime->m_modules["temp/call_types.temp.nlm"]->Main(&ctx, args));
1435// //@todo Контроль переполнения при операциях для типизированных переменных
1436// //????????????????
1437// //@todo Такой же как и для остальных операций
1438// //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1439// // ASSERT_THROW(opts->m_modules["temp/call_types.temp.nlm"]->Main(&ctx,
1440// // args), newlang_exception);
1441//
1442//#undef FUNC_ARG
1443//#undef FUNC_RES
1444//
1445//}
1446
1447
1448//
1449//#include "clang/Frontend/FrontendActions.h"
1450//#include "clang/Tooling/CommonOptionsParser.h"
1451//#include "clang/Tooling/Tooling.h"
1453//#include "llvm/Support/CommandLine.h"
1454//#include "clang/ASTMatchers/ASTMatchers.h"
1455//#include "clang/ASTMatchers/ASTMatchFinder.h"
1456//#include <iostream>
1457//
1458//
1459//using namespace clang;
1460//using namespace clang::ast_matchers;
1461//using namespace clang::tooling;
1462//using namespace llvm;
1463//
1467//static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
1468//
1470//static cl::extrahelp MoreHelp("\nMore help text...");
1471//
1472//DeclarationMatcher methodMatcher = clang::ast_matchers::decl(clang::ast_matchers::anything()).bind("methods"); //methodDecl(isPublic(), unless(isImplicit()))
1473//
1474//class MethodPrinter : public MatchFinder::MatchCallback {
1475//public:
1476//
1477// virtual void run(const MatchFinder::MatchResult &Result) {
1478// if (const CXXMethodDecl * md = Result.Nodes.getNodeAs<clang::CXXMethodDecl>("methods")) {
1479// lastPublicMethodName = md->getNameAsString();
1480// }
1481// }
1482//
1483// std::string lastPublicMethodName;
1484//};
1485//
1514#endif // BUILD_UNITTEST
int result
Definition lexer.l:367
#define LOG_RUNTIME(format,...)
Definition logger.h:26
#define LOG_DEBUG(...)
Definition logger.h:119
#define ASSERT(condition)
Definition logger.h:60
Definition nlc.h:59
bool isStringChar(ObjType t)
Definition types.h:759
bool isStaticName(const std::string_view name)
Definition types.h:1061
bool isStringWide(ObjType t)
Definition types.h:764
bool isArithmeticType(ObjType t)
Definition types.h:752
bool isLocalName(const std::string_view name)
Definition types.h:1074
const char * toCXXType(ObjType type, bool int_bool)
Definition types.h:552
bool isFieldName(const std::string_view name)
Definition types.h:1065
std::shared_ptr< Term > TermPtr
Definition variable.h:33
bool isGlobalScope(const std::string_view name)
Definition types.h:1078
const char * toCXXRef(const std::string_view ref)
Definition types.h:602
bool isNativeName(const std::string_view name)
Definition types.h:1102
ObjType
Definition types.h:524
std::string Dump(const T &iterable)
Definition logger.h:306