4#include <clang/AST/ASTConcept.h>
5#include <clang/Sema/SemaConcept.h>
6#include <clang/Driver/Driver.h>
7#include <clang/Driver/Compilation.h>
9#include <llvm/IR/LegacyPassManager.h>
10#include <llvm/MC/TargetRegistry.h>
11#include <llvm/Support/CodeGen.h>
13#include <llvm/Support/Signals.h>
15#include <llvm/Analysis/AliasAnalysis.h>
16#include <clang/Frontend/TextDiagnosticPrinter.h>
26#include "build_options.data"
27#include "include_h_i.data"
46 case L
'а': str.append(L
"a");
48 case L
'б': str.append(L
"b");
50 case L
'в': str.append(L
"v");
52 case L
'г': str.append(L
"g");
54 case L
'д': str.append(L
"d");
56 case L
'е': str.append(L
"e");
58 case L
'ё': str.append(L
"ye");
60 case L
'ж': str.append(L
"zh");
62 case L
'з': str.append(L
"z");
64 case L
'и': str.append(L
"i");
66 case L
'й': str.append(L
"y");
68 case L
'к': str.append(L
"k");
70 case L
'л': str.append(L
"l");
72 case L
'м': str.append(L
"m");
74 case L
'н': str.append(L
"n");
76 case L
'о': str.append(L
"o");
78 case L
'п': str.append(L
"p");
80 case L
'р': str.append(L
"r");
82 case L
'с': str.append(L
"s");
84 case L
'т': str.append(L
"t");
86 case L
'у': str.append(L
"u");
88 case L
'ф': str.append(L
"f");
90 case L
'х': str.append(L
"h");
92 case L
'ц': str.append(L
"z");
94 case L
'ч': str.append(L
"ch");
96 case L
'ш': str.append(L
"sh");
98 case L
'щ': str.append(L
"sch");
100 case L
'ы': str.append(L
"y");
102 case L
'э': str.append(L
"e");
104 case L
'ю': str.append(L
"yu");
106 case L
'я': str.append(L
"ya");
108 case L
'А': str.append(L
"A");
110 case L
'Б': str.append(L
"B");
112 case L
'В': str.append(L
"V");
114 case L
'Г': str.append(L
"G");
116 case L
'Д': str.append(L
"D");
118 case L
'Е': str.append(L
"E");
120 case L
'Ё': str.append(L
"YE");
122 case L
'Ж': str.append(L
"ZH");
124 case L
'З': str.append(L
"Z");
126 case L
'И': str.append(L
"I");
128 case L
'Й': str.append(L
"Y");
130 case L
'К': str.append(L
"K");
132 case L
'Л': str.append(L
"L");
134 case L
'М': str.append(L
"M");
136 case L
'Н': str.append(L
"N");
138 case L
'О': str.append(L
"O");
140 case L
'П': str.append(L
"P");
142 case L
'Р': str.append(L
"R");
144 case L
'С': str.append(L
"S");
146 case L
'Т': str.append(L
"T");
148 case L
'У': str.append(L
"U");
150 case L
'Ф': str.append(L
"F");
152 case L
'Х': str.append(L
"H");
154 case L
'Ц': str.append(L
"Z");
156 case L
'Ч': str.append(L
"CH");
158 case L
'Ш': str.append(L
"SH");
160 case L
'Щ': str.append(L
"SCH");
162 case L
'Ы': str.append(L
"Y");
164 case L
'ъ': str.append(L
"_");
165 case L
'ь': str.append(L
"_");
166 case L
'Ь': str.append(L
"_");
167 case L
'Ъ': str.append(L
"_");
169 case L
'Э': str.append(L
"E");
171 case L
'Ю': str.append(L
"YU");
173 case L
'Я': str.append(L
"YA");
176 str.append(std::to_wstring(
static_cast<unsigned int> (c)));
190 result += std::to_string(strlen(name));
192 result +=
"PN7newlang7ContextERNS_4ObjectE";
202 std::string
result(
"_ZN7newlang");
203 result += std::to_string(name.size());
205 result +=
isConstName(name) ?
"EPNS_7ContextERNS_6ObjectE" :
"EPKNS_7ContextERKNS_6ObjectE";
211#define ALLOW_CHAR L"_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
212 static const std::wstring first_char(
ALLOW_CHAR);
213 static const std::wstring next_char(L
"0123456789" ALLOW_CHAR);
215 std::wstring_convert < std::codecvt_utf8<wchar_t>,
wchar_t> converter;
216 std::wstring temp = converter.from_bytes(name);
220 size_t len = temp.size();
221 for (
size_t i = 0; i < len; i++) {
222 if (i == 0 && first_char.find(temp[i]) != std::wstring::npos) {
224 }
else if (i != 0 && next_char.find(temp[i]) != std::wstring::npos) {
231 return converter.to_bytes(
result);
362std::unique_ptr<llvm::Module>
JIT::MakeLLVMModule(
const std::string_view source, std::vector<std::string> extra_opts, std::string temp_dir) {
364 clang::CompilerInstance compilerInstance;
365 auto& compilerInvocation = compilerInstance.getInvocation();
380 std::string triple = LLVMGetDefaultTargetTriple();
382 std::vector<std::string> run_opts;
383 run_opts.push_back(triple);
384 run_opts.back().insert(0,
"-triple=");
386 run_opts.push_back(
"-xc++");
393 std::string build_options_string;
394 for (
size_t i = 0; i < newlang_build_options_size; i++) {
395 build_options_string += newlang_build_options_arr[i];
396 build_options_string +=
" ";
398 std::vector<std::string> build_opts =
RunTime::SplitChar(build_options_string,
" \t\r\n");
399 build_options_string.clear();
401 run_opts.insert(run_opts.end(), build_opts.begin(), build_opts.end());
402 run_opts.insert(run_opts.end(), extra_opts.begin(), extra_opts.end());
404 for (
auto &elem : run_opts) {
405 if (elem.find(
"-D") == 0) {
423 pipe2(codeInPipe, O_NONBLOCK);
426 int pipe_sz_save = fcntl(codeInPipe[1], F_GETPIPE_SZ, 0);
428 std::string temp_file;
429 std::string obj_file;
431 if (pipe_sz_save / 2 < source.size()) {
433 close(codeInPipe[1]);
435 temp_file = temp_dir.empty() ?
m_temp_dir : temp_dir;
436 temp_file +=
"/module_XXXXXX";
437 fd_temp = mkstemp(temp_file.data());
439 LOG_RUNTIME(
"Fail create temp file %s!", temp_file.c_str());
442 writen = write(fd_temp, source.begin(), source.size());
444 if (writen != source.size()) {
445 LOG_RUNTIME(
"Write error to temp file %s!", temp_file.c_str());
448 obj_file = temp_file;
451 run_opts.push_back(
"-o");
452 run_opts.push_back(obj_file);
453 run_opts.push_back(temp_file.c_str());
459 int writen = write(codeInPipe[1], source.begin(), source.size());
461 if (writen != source.size()) {
462 LOG_RUNTIME(
"Write PIPE error: only %d of required %d bytes were written!", writen, (
int) source.size());
465 close(codeInPipe[1]);
466 dup2(codeInPipe[0], STDIN_FILENO);
468 run_opts.push_back(
"-");
472 std::vector<const char*> itemcstrs;
473 for (
unsigned idx = 0; idx < run_opts.size(); idx++) {
476 itemcstrs.push_back(run_opts[idx].c_str());
481 clang::CompilerInvocation::CreateFromArgs(compilerInvocation,
482 llvm::ArrayRef<const char *>(itemcstrs.data(),
485 auto& languageOptions = compilerInvocation.getLangOpts();
486 auto& preprocessorOptions = compilerInvocation.getPreprocessorOpts();
487 auto& targetOptions = compilerInvocation.getTargetOpts();
489 auto& frontEndOptions = compilerInvocation.getFrontendOpts();
492 auto& headerSearchOptions = compilerInvocation.getHeaderSearchOpts();
495 auto& codeGenOptions = compilerInvocation.getCodeGenOpts();
498 targetOptions.Triple = LLVMGetDefaultTargetTriple();
503 LLVMContextRef ctx = LLVMContextCreate();
504 std::unique_ptr<clang::CodeGenAction> action = std::make_unique<clang::EmitLLVMOnlyAction>((llvm::LLVMContext *)ctx);
506 if (!compilerInstance.ExecuteAction(*action)) {
511 std::unique_ptr<llvm::Module> module = action->takeModule();
517 std::filesystem::remove(temp_file);
584bool JIT::MakeObjFile(
const std::string_view filename, llvm::Module &module,
const std::vector<std::string> opts) {
588 std::string triple = LLVMGetDefaultTargetTriple();
591 auto Target = llvm::TargetRegistry::lookupTarget(triple,
Error);
598 auto CPU =
"generic";
601 llvm::TargetOptions opt;
602 auto RM = std::optional<llvm::Reloc::Model>();
603 auto TargetMachine = Target->createTargetMachine(triple, CPU, Features, opt, RM);
605 module.setDataLayout(TargetMachine->createDataLayout());
606 module.setTargetTriple(triple);
610 llvm::raw_fd_ostream dest(filename.begin(), EC, llvm::sys::fs::OF_None);
612 llvm::legacy::PassManager pass;
613 auto FileType = llvm::CodeGenFileType::ObjectFile;
615 if (TargetMachine->addPassesToEmitFile(pass, dest,
nullptr, FileType)) {
616 llvm::errs() <<
"TargetMachine can't emit a file of this type";
624bool JIT::LinkObjToExec(
const std::string_view execname, std::vector<std::string> objs, std::vector<std::string> opts) {
626 clang::driver::Driver TheDriver(
"", LLVMGetDefaultTargetTriple(), *
pDiagnosticsEngine);
629 objs.insert(objs.begin(), opts.begin(), opts.end());
631 objs.insert(objs.begin(),
"-g");
632 objs.push_back(
"-o");
633 objs.push_back(execname.begin());
637 std::vector<const char*> args;
638 for (
unsigned idx = 0; idx < objs.size(); idx++) {
641 args.push_back(objs[idx].c_str());
648 std::unique_ptr<clang::driver::Compilation> C(TheDriver.BuildCompilation(args));
650 if (C && !C->containsError()) {
651 llvm::SmallVector<std::pair<int, const clang::driver::Command *>, 4> FailingCommands;
652 TheDriver.ExecuteCompilation(*C, FailingCommands);
667 if (term->isBlock()) {
668 for (
auto &elem : term->m_block) {
672 if (term->isCreate() && term->m_left->isCall()) {
676 result +=
"extern \"C\" ";
686 if (func->m_normalized.empty()) {
687 NL_PARSER(func,
"Has no internal name! AST analysis required!");
690 result += func->m_normalized.getMangledName(module);
696 std::string comment = term->toString();
698 comment +=
" at line: ";
699 comment += std::to_string(term->m_line);
705 std::string comment(src);
706 comment = std::regex_replace(comment, std::regex(
"\n"),
"\\n");
707 comment = std::regex_replace(comment, std::regex(
"\""),
"@\"");
726 if (source.compare(ast->m_text) == 0) {
732 LOG_RUNTIME(
"Options '--nlc-no-link-rt' not allowed!");
738 LOG_RUNTIME(
"Options '--nlc-no-link-rt' not allowed!");
755std::string
JIT::MakeMainEmbed(
const std::string_view embed_source,
const std::vector<std::string> &include) {
757 result +=
"/*\n* Generate NewLang JIT::MakeMainEmbed";
763 std::string filename;
764 for (
auto &elem : include) {
766 if (elem.find(
"\\") == 0) {
768 filename = elem.substr(1);
774 std::replace(filename.begin(), filename.end(),
'\\',
'/');
777 result +=
"\n\nnamespace newlang {\n";
780 result +=
"int main(const int argc, const char* argv[], const char* penv[]) {\n\n";
793 std::string
result(embed);
795 size_t pos =
result.find(
"@\\");
796 while (pos != std::string::npos) {
797 include.push_back(
result.substr(pos + 2,
result.find_first_of(
" \t\n\r*/$#\"'[]%;:", pos + 2) - pos - 2));
798 pos =
result.find(
"@\\", pos + 2);
802 std::string arg_name;
803 std::string arg_place;
804 for (
size_t i = 0; i < args->size(); i++) {
806 arg_name =
"@$" + std::to_string(i);
807 arg_place =
"in[" + std::to_string(i) +
"]";
808 result = std::regex_replace(
result, std::regex(arg_name), arg_place);
811 for (
auto &elem : *args) {
814 arg_place =
"in[\"" + arg_name +
"\"]";
815 arg_name =
"@$" + arg_name;
816 result = std::regex_replace(
result, std::regex(arg_name), arg_place);
824 for (
size_t i = 0; i < newlang_include_h_i_size; i++) {
825 result += newlang_include_h_i_arr[i];
829 result +=
"/*\n* Generate NewLang JIT::MakeCodeModule";
849 func_module->m_is_call =
true;
850 func_module->m_normalized =
NormalizeName(func_module->m_text);
855 result +=
" return nullptr;\n";
860 result +=
"/*\n* End generate JIT::MakeCodeModule";
931 if (term->isBlock()) {
932 for (
auto &elem : term->m_block) {
936 if (term->isCreate()) {
937 if (term->m_left->isCall()) {
941 output +=
"extern \"C\" ";
2434 if (type == LLVMInt1Type() || type == LLVMInt8Type() || type == LLVMInt16Type() || type == LLVMInt32Type() || type == LLVMInt64Type()) {
2436 }
else if (type == LLVMFloatType() || type == LLVMDoubleType()) {
2438 }
else if (type == LLVMPointerType(LLVMInt8Type(), 0)) {
2440 return LLVMCreateGenericValueOfPointer((
void *) obj.
m_value.c_str());
2442 ASSERT(std::holds_alternative<void *>(obj.
m_var));
2443 return LLVMCreateGenericValueOfPointer(std::get<void *>(obj.
m_var));
2445 }
else if (type == LLVMPointerType(LLVMInt32Type(), 0)) {
2448 return LLVMCreateGenericValueOfPointer((
void *) obj.
m_string.c_str());
2458 int64_t value = LLVMGenericValueToInt(ref,
true);
2459 unsigned width = LLVMGenericValueIntWidth(ref);
2462 return Obj::CreateValue((
double) LLVMGenericValueToFloat(llvm_type, ref), type);
2464 if (llvm_type == LLVMInt8Type()) {
2465 return Obj::CreateString(std::string(1, (
char) LLVMGenericValueToInt(ref,
false)));
2468 return Obj::CreateString(std::string((
const char *) LLVMGenericValueToPointer(ref)));
2471 if (llvm_type == LLVMInt32Type()) {
2472 return Obj::CreateString(std::wstring(1, (
wchar_t) LLVMGenericValueToInt(ref,
false)));
2475 return Obj::CreateString(std::wstring((
const wchar_t *)LLVMGenericValueToPointer(ref)));
2480 result->m_var = LLVMGenericValueToPointer(ref);
2490 return LLVMVoidType();
2492 return LLVMInt1Type();
2496 return LLVMInt8Type();
2499 return LLVMInt16Type();
2502 return LLVMInt32Type();
2506 return LLVMInt64Type();
2510 return LLVMFloatType();
2514 return LLVMDoubleType();
2519 return LLVMPointerType(LLVMInt8Type(), 0);
2524 return LLVMPointerType(LLVMInt16Type(), 0);
2528 return LLVMPointerType(LLVMInt32Type(), 0);
2537 return std::make_shared<Parser>(
m_macro,
nullptr,
m_diag,
true,
this);
2542 LOG_RUNTIME(
"File or module '%s' not found!", file.c_str());
2544 std::string source =
ReadFile(file.c_str());
2551 return Run(source, args);
2564 if (
m_ctx.empty()) {
2565 m_ctx.push_back(std::make_shared<Context>(
this));
2576 (*ast)->m_block.push_back(temp);
2581 m_diag->m_error_count = 0;
2587 if (
m_diag->m_error_count) {
2598 (*ast)->m_block.pop_back();
2646 data.
name.assign(module_name);
2650 llvm::raw_string_ostream code(data.
bytecode);
2651 llvm::WriteBitcodeToFile(*bc, code);
2662 DiagOpts =
new clang::DiagnosticOptions;
2688 VERIFY(
CreateMacro(
"@@ match( ... ) @@ ::= @@ [ @$... ] @__PRAGMA_EXPECTED__( @\\ =>, @\\ ==>, @\\ ===>, @\\ ~>, @\\ ~~>, @\\ ~~~> ) @@"));
2695 VERIFY(
CreateMacro(
"@@ super @@ ::= @@ $$ @@ ##< Super (parent) class or function"));
2696 VERIFY(
CreateMacro(
"@@ latter @@ ::= @@ $^ @@ ##< Result of the last operation"));
2701 VERIFY(
CreateMacro(
"@@ forward @@ ::= @@ +- $^ -+ @@ ##< Forward latter result or exception"));
2722 VERIFY(
CreateMacro(
"@@ declare( obj ) @@ ::= @@ @$obj ::= ... @@ ##< Forward declaration of the object"));
2726 VERIFY(
CreateMacro(
"@@ typedef(cnt) @@ ::= @@ @__PRAGMA_TYPE_DEFINE__(@$cnt) @@ ##< Disable warning when defining a type inside a namespace"));
2729 VERIFY(
CreateMacro(
"@@ co_yield $val @@ ::= @@ __ANNOTATION_CHECK__(coroutine) $:: :: -- @$val -- @@"));
2730 VERIFY(
CreateMacro(
"@@ co_await @@ ::= @@ __ANNOTATION_CHECK__(coroutine) $:: :: +- @@"));
2731 VERIFY(
CreateMacro(
"@@ co_return $val @@ ::= @@ __ANNOTATION_CHECK__(coroutine) $:: :: ++ @$val ++ @@"));
2744 VERIFY(
CreateMacro(
"@@ timeit( call, ... ) @@ ::= @@ { __start_point__ := ::Base::__timeit__(); @$call ; ::Base::__timeit__( __start_point__, @# @$call, @$... ); } @@ ##< Measure execution time of function call"));
2764 VERIFY(
CreateMacro(
"@@ static_assert(...) @@ ::= @@ @__PRAGMA_STATIC_ASSERT__(@$... ) @@"));
2767 VERIFY(
CreateMacro(
"@@ assert(value, ...) @@ ::= @@ [:Bool(@$value)==0]-->{ ::Base::__assert_abort__(@# @$value, @$value, @$... ) } @@"));
2768 VERIFY(
CreateMacro(
"@@ verify(value, ...) @@ ::= @@ [:Bool(@$value)==0]-->{ ::Base::__assert_abort__(@# @$value, @$value, @$... ) } @@"));
2790 std::string
result(
"\n");
2791 llvm::raw_string_ostream stack(
result);
2792 llvm::sys::PrintStackTrace(stack, 1);
2797 LLVMLoadLibraryPermanently(
nullptr);
2798 return LLVMSearchForAddressOfSymbol(name.begin());
static std::string MakeInclude(const TermPtr &ast)
bool Analyze(TermPtr term, NameLookupStack *stack_ptr=nullptr)
static LatterType Execute(Module &module, TermPtr ast, Context *runner)
static std::string ExtractStaticVars(const TermPtr &ast, const std::string_view module)
static std::string ReplaceObjectInEmbedSource(const std::string_view embed, std::vector< std::string > &include, const TermPtr args=nullptr)
std::string MakeCodeFunction(const TermPtr &term)
static std::string MakeCommentPlace(const TermPtr &term)
static std::string MakeMain(const std::vector< std::string > &include)
bool LinkObjToExec(const std::string_view filename, std::vector< std::string > objs, std::vector< std::string > opts={})
std::vector< std::string > m_includes
JIT(const StringArray &args={})
std::string MakeCodeModule(const TermPtr &term, std::string_view name, bool is_main)
clang::IntrusiveRefCntPtr< clang::DiagnosticIDs > pDiagIDs
void MakeFunctionRecursive_(const TermPtr &term, std::string &output, const std::string_view module)
ObjPtr Run(const std::string_view str, Obj *args=nullptr)
static bool LLVMInitializeJIT()
std::vector< ModulePtr > m_module
clang::IntrusiveRefCntPtr< clang::DiagnosticOptions > DiagOpts
clang::TextDiagnosticPrinter * textDiagPrinter
static std::string RegExpInlineComment(const std::string_view src)
std::unique_ptr< llvm::Module > MakeLLVMModule(std::string_view source, const std::vector< std::string > opts, std::string temp_dir="")
static std::string ExtractFunctionDecls(const TermPtr &ast, const std::string_view module)
std::vector< std::shared_ptr< Context > > m_ctx
ObjPtr RunFile(std::string file, Obj *args=nullptr)
clang::DiagnosticsEngine * pDiagnosticsEngine
std::string MakeApplicationSource(const TermPtr &ast)
static std::string MakeFunctionPrototype(const TermPtr &func, const std::string_view module)
bool MakeObjFile(const std::string_view filename, llvm::Module &module, const std::vector< std::string > opts)
static std::string MakeMainEmbed(const std::string_view embed_source, const std::vector< std::string > &include)
static bool LLVMInitialize()
static TermPtr MainArgs()
std::string MakeFuncDeclarations_(const TermPtr &term)
std::string MakeCodeRepl(const std::string_view source, const std::string_view name)
static std::string MakeBodyFunction(const TermPtr &ast)
bool ModuleCreate(FileModule &data, const std::string_view source)
bool CreateMacro(const std::string_view text)
VariablePair & GetVariablePair(bool editable=false)
static std::string GetStackTrace()
static ObjPtr CreateString(const std::string_view str, Sync *sync=nullptr)
std::variant< std::monostate, int64_t, double, void *, bool *, int8_t *, int16_t *, int32_t *, int64_t *, float *, double *, NativeData, std::string, TermPtr, Iterator< Obj > > m_var
ObjType m_var_type_current
Текущий тип значения объекта
double GetValueAsNumber() const
static std::enable_if< std::is_same< T, std::string >::value||std::is_same< T, constchar * >::value, ObjPtr >::type CreateValue(T value, Sync *sync=nullptr)
std::wstring m_string
Содержит строку широких символов
std::string m_value
Содержит байтовую строку или байтовый массив с данными для представления в нативном виде (Struct,...
int64_t GetValueAsInteger() const
static ObjPtr CreateNone(Sync *sync=nullptr)
static ObjPtr CreateType(ObjType type, ObjType fixed=ObjType::None, bool is_init=false, Sync *sync=nullptr)
static size_t ParseTerm(TermPtr &term, const BlockType &buffer, const size_t skip=0, bool pragma_enable=true)
static std::string GetCurrentTimeStamp(time_t ts=std::time(NULL))
static void * GetNativeAddress(void *handle, const std::string_view name)
static bool ExpandFileName(std::string &filename)
static std::vector< std::string > SplitChar(std::string_view str, const std::string_view delimiter)
static TermPtr Create(TermID id, const char *text, parser::token_type lex_type=parser::token_type::END, size_t len=std::string::npos, location *loc=nullptr, std::shared_ptr< std::string > source=nullptr)
static TermPtr CreateName(std::string name, TermID id=TermID::NAME)
static TermPtr CreateDict()
ObjPtr GetValueAsObject() const
LLVMTypeRef toLLVMType(ObjType t, bool none_if_error)
ObjPtr CreateFromGenericValue(ObjType type, LLVMGenericValueRef ref, LLVMTypeRef llvm_type)
LLVMGenericValueRef GetGenericValueRef(Obj &obj, LLVMTypeRef type)
#define NEWLANG_INDENT_OP
#define LOG_RUNTIME(format,...)
#define LOG_PARSER(format,...)
#define ASSERT(condition)
bool isConstName(const std::string_view name)
bool isFloatingType(ObjType t)
std::string MakeName(std::string name)
std::shared_ptr< Parser > ParserPtr
bool isIntegralType(ObjType t, bool includeBool)
std::string MangaledFuncCPP(const char *name, const char *space=nullptr)
std::shared_ptr< Term > TermPtr
std::shared_ptr< Obj > ObjPtr
std::vector< std::string > StringArray
bool Tranliterate(const wchar_t c, std::wstring &str)
std::string MangaledFunc(const std::string name)
std::string MangleName(const char *name)
std::string ReadFile(const char *fileName)
T repeat(T str, const std::size_t n)
std::string NormalizeName(const std::string_view name)
const char * toString(TermID type)
#define SCOPE_LOCK_WRITE(THIS)
std::string GetIndent(int64_t offset=0)
#define NL_PARSER(term, format,...)
#define VERSION_SOURCE_FULL_ID