See More

#include #include #include #include #define CLI11_HAS_FILESYSTEM 0 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_BUILD_TO_WASM #include #endif #ifdef HAVE_LFORTRAN_RAPIDJSON #include #include #include #endif extern std::string lcompilers_unique_ID_separate_compilation; namespace { using LCompilers::endswith; using LCompilers::CompilerOptions; using LCompilers::LPython::parse_python_file; enum class Backend { llvm, cpp, c, x86, wasm, wasm_x86, wasm_x64, python }; std::string remove_extension(const std::string& filename) { size_t lastdot = filename.find_last_of("."); if (lastdot == std::string::npos) return filename; return filename.substr(0, lastdot); } std::string remove_path(const std::string& filename) { size_t lastslash = filename.find_last_of("/"); if (lastslash == std::string::npos) return filename; return filename.substr(lastslash+1); } std::string get_kokkos_dir() { char *env_p = std::getenv("LFORTRAN_KOKKOS_DIR"); if (env_p) return env_p; std::cerr << "The code C++ generated by the C++ LPython backend uses the Kokkos library" << std::endl; std::cerr << "(https://github.com/kokkos/kokkos). Please define the LFORTRAN_KOKKOS_DIR" << std::endl; std::cerr << "environment variable to point to the Kokkos installation." << std::endl; throw LCompilers::LCompilersException("LFORTRAN_KOKKOS_DIR is not defined"); } #ifdef HAVE_LFORTRAN_LLVM #endif int emit_tokens(const std::string &infile, bool line_numbers, const CompilerOptions &compiler_options) { std::string input = LCompilers::read_file_ok(infile); // Src -> Tokens Allocator al(64*1024*1024); std::vector toks; std::vector<:lpython::yystype> stypes; std::vector<:location> locations; LCompilers::diag::Diagnostics diagnostics; auto res = LCompilers::LPython::tokens(al, input, diagnostics, &stypes, &locations); LCompilers::LocationManager lm; { LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } std::cerr << diagnostics.render(lm, compiler_options); if (res.ok) { toks = res.result; } else { LCOMPILERS_ASSERT(diagnostics.has_error()) return 1; } for (size_t i=0; i < toks.size(); i++) { std::cout << LCompilers::LPython::pickle_token(toks[i], stypes[i]); if (line_numbers) { std::cout << " " << locations[i].first << ":" << locations[i].last; } std::cout << std::endl; } return 0; } int emit_ast(const std::string &infile, const std::string &runtime_library_dir, CompilerOptions &compiler_options) { Allocator al(4*1024); LCompilers::diag::Diagnostics diagnostics; LCompilers::Result<:lpython::ast::ast_t> r = parse_python_file( al, runtime_library_dir, infile, diagnostics, 0, compiler_options.new_parser); if (diagnostics.diagnostics.size() > 0) { LCompilers::LocationManager lm; { LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } std::cerr << diagnostics.render(lm, compiler_options); } if (!r.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) return 1; } LCompilers::LPython::AST::ast_t* ast = r.result; if (compiler_options.po.tree) { std::cout << LCompilers::LPython::pickle_tree_python(*ast, compiler_options.use_colors) << std::endl; } else if (compiler_options.po.json) { LCompilers::LocationManager lm; { LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } std::cout << LCompilers::LPython::pickle_json(*ast, lm) << std::endl; } else if (compiler_options.po.visualize) { LCompilers::LocationManager lm; { LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } LCompilers::Result<:string> r = LCompilers::LPython::pickle_json(*ast, lm); return visualize_json(r.result, compiler_options.platform); } else { std::cout << LCompilers::LPython::pickle_python(*ast, compiler_options.use_colors, compiler_options.indent) << std::endl; } return 0; } int emit_asr(const std::string &infile, LCompilers::PassManager& pass_manager, const std::string &runtime_library_dir, bool with_intrinsic_modules, CompilerOptions &compiler_options) { Allocator al(4*1024); LCompilers::diag::Diagnostics diagnostics; LCompilers::LocationManager lm; { LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } LCompilers::Result<:lpython::ast::ast_t> r1 = parse_python_file( al, runtime_library_dir, infile, diagnostics, 0, compiler_options.new_parser); std::cerr << diagnostics.render(lm, compiler_options); if (!r1.ok) { return 1; } LCompilers::LPython::AST::ast_t* ast = r1.result; diagnostics.diagnostics.clear(); LCompilers::Result<:asr::translationunit_t> r = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); std::cerr << diagnostics.render(lm, compiler_options); if (!r.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) return 2; } LCompilers::ASR::TranslationUnit_t* asr = r.result; compiler_options.po.always_run = true; compiler_options.po.run_fun = "f"; pass_manager.apply_passes(al, asr, compiler_options.po, diagnostics); if (compiler_options.po.tree) { std::cout << LCompilers::pickle_tree(*asr, compiler_options.use_colors, with_intrinsic_modules) << std::endl; } else if (compiler_options.po.json) { std::cout << LCompilers::pickle_json(*asr, lm, compiler_options.po.no_loc, with_intrinsic_modules) << std::endl; } else if (compiler_options.po.visualize) { std::string astr_data_json = LCompilers::pickle_json(*asr, lm, compiler_options.po.no_loc, with_intrinsic_modules); return visualize_json(astr_data_json, compiler_options.platform); } else { std::cout << LCompilers::pickle(*asr, compiler_options.use_colors, compiler_options.indent, with_intrinsic_modules) << std::endl; } return 0; } int emit_cpp(const std::string &infile, const std::string &runtime_library_dir, CompilerOptions &compiler_options) { Allocator al(4*1024); LCompilers::diag::Diagnostics diagnostics; LCompilers::LocationManager lm; { LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } LCompilers::Result<:lpython::ast::ast_t> r = parse_python_file( al, runtime_library_dir, infile, diagnostics, 0, compiler_options.new_parser); std::cerr << diagnostics.render(lm, compiler_options); if (!r.ok) { return 1; } LCompilers::LPython::AST::ast_t* ast = r.result; diagnostics.diagnostics.clear(); LCompilers::Result<:asr::translationunit_t> r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); std::cerr << diagnostics.render(lm, compiler_options); if (!r1.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) return 2; } LCompilers::ASR::TranslationUnit_t* asr = r1.result; diagnostics.diagnostics.clear(); auto res = LCompilers::asr_to_cpp(al, *asr, diagnostics, compiler_options, 0); std::cerr << diagnostics.render(lm, compiler_options); if (!res.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) return 3; } std::cout << res.result; return 0; } int emit_c(const std::string &infile, const std::string &runtime_library_dir, LCompilers::PassManager& pass_manager, CompilerOptions &compiler_options) { Allocator al(4*1024); LCompilers::diag::Diagnostics diagnostics; LCompilers::LocationManager lm; { LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } LCompilers::Result<:lpython::ast::ast_t> r = parse_python_file( al, runtime_library_dir, infile, diagnostics, 0, compiler_options.new_parser); std::cerr << diagnostics.render(lm, compiler_options); if (!r.ok) { return 1; } LCompilers::LPython::AST::ast_t* ast = r.result; diagnostics.diagnostics.clear(); LCompilers::Result<:asr::translationunit_t> r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); std::cerr << diagnostics.render(lm, compiler_options); if (!r1.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) return 2; } LCompilers::ASR::TranslationUnit_t* asr = r1.result; // Apply ASR passes pass_manager.use_default_passes(true); compiler_options.po.always_run = true; compiler_options.po.run_fun = "f"; compiler_options.po.c_skip_bindpy_pass = true; pass_manager.apply_passes(al, asr, compiler_options.po, diagnostics); diagnostics.diagnostics.clear(); auto res = LCompilers::asr_to_c(al, *asr, diagnostics, compiler_options, 0); std::cerr << diagnostics.render(lm, compiler_options); if (!res.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) return 3; } std::cout << res.result; return 0; } int emit_c_to_file(const std::string &infile, const std::string &outfile, const std::string &runtime_library_dir, LCompilers::PassManager& pass_manager, CompilerOptions &compiler_options) { Allocator al(4*1024); LCompilers::diag::Diagnostics diagnostics; LCompilers::LocationManager lm; { LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } LCompilers::Result<:lpython::ast::ast_t> r = parse_python_file( al, runtime_library_dir, infile, diagnostics, 0, compiler_options.new_parser); std::cerr << diagnostics.render(lm, compiler_options); if (!r.ok) { return 1; } LCompilers::LPython::AST::ast_t* ast = r.result; diagnostics.diagnostics.clear(); LCompilers::Result<:asr::translationunit_t> r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); std::cerr << diagnostics.render(lm, compiler_options); if (!r1.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) return 2; } LCompilers::ASR::TranslationUnit_t* asr = r1.result; compiler_options.po.run_fun = "f"; compiler_options.po.always_run = true; compiler_options.po.c_skip_bindpy_pass = true; pass_manager.use_default_passes(true); pass_manager.apply_passes(al, asr, compiler_options.po, diagnostics); diagnostics.diagnostics.clear(); auto res = LCompilers::asr_to_c(al, *asr, diagnostics, compiler_options, 0); std::cerr << diagnostics.render(lm, compiler_options); if (!res.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) return 3; } FILE *fp; fp = fopen(outfile.c_str(), "w"); fputs(res.result.c_str(), fp); fclose(fp); return 0; } int emit_python(const std::string &infile, const std::string &runtime_library_dir, CompilerOptions &compiler_options) { Allocator al(4*1024); LCompilers::diag::Diagnostics diagnostics; LCompilers::LocationManager lm; { LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } LCompilers::Result<:lpython::ast::ast_t> r = parse_python_file( al, runtime_library_dir, infile, diagnostics, 0, compiler_options.new_parser); std::cerr << diagnostics.render(lm, compiler_options); if (!r.ok) { return 1; } LCompilers::LPython::AST::ast_t* ast = r.result; diagnostics.diagnostics.clear(); // AST -> ASR LCompilers::Result<:asr::translationunit_t> r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); std::cerr << diagnostics.render(lm, compiler_options); if (!r1.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) return 2; } LCompilers::ASR::TranslationUnit_t* asr = r1.result; diagnostics.diagnostics.clear(); // ASR -> LPython bool color = false; int indent = 0; LCompilers::Result<:string> res = LCompilers::asr_to_python(al, *asr, diagnostics, compiler_options, color, indent); std::cerr << diagnostics.render(lm, compiler_options); if (!res.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) return 3; } std::cout << res.result; return 0; } int emit_wat(const std::string &infile, const std::string &runtime_library_dir, CompilerOptions &compiler_options) { Allocator al(4*1024); LCompilers::diag::Diagnostics diagnostics; LCompilers::LocationManager lm; { LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } LCompilers::Result<:lpython::ast::ast_t> r = parse_python_file( al, runtime_library_dir, infile, diagnostics, 0, compiler_options.new_parser); std::cerr << diagnostics.render(lm, compiler_options); if (!r.ok) { return 1; } LCompilers::LPython::AST::ast_t* ast = r.result; diagnostics.diagnostics.clear(); LCompilers::Result<:asr::translationunit_t> r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); std::cerr << diagnostics.render(lm, compiler_options); if (!r1.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) return 2; } LCompilers::ASR::TranslationUnit_t* asr = r1.result; diagnostics.diagnostics.clear(); LCompilers::Result<:vec>> r2 = LCompilers::asr_to_wasm_bytes_stream(*asr, al, diagnostics, compiler_options); std::cerr << diagnostics.render(lm, compiler_options); if (!r2.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) return 3; } diagnostics.diagnostics.clear(); LCompilers::Result<:string> res = LCompilers::wasm_to_wat(r2.result, al, diagnostics); std::cerr << diagnostics.render(lm, compiler_options); if (!res.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) return 4; } std::cout << res.result; return 0; } int dump_all_passes(const std::string &infile, const std::string &runtime_library_dir, CompilerOptions &compiler_options) { std::string input = LCompilers::read_file_ok(infile); Allocator al(4*1024); LCompilers::LocationManager lm; LCompilers::diag::Diagnostics diagnostics; { LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); lm.file_ends.push_back(input.size()); } LCompilers::Result<:lpython::ast::ast_t> r = parse_python_file( al, runtime_library_dir, infile, diagnostics, 0, compiler_options.new_parser); std::cerr << diagnostics.render(lm, compiler_options); if (!r.ok) { return 1; } LCompilers::LPython::AST::ast_t* ast = r.result; diagnostics.diagnostics.clear(); LCompilers::Result<:asr::translationunit_t> r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); std::cerr << diagnostics.render(lm, compiler_options); if (r1.ok) { LCompilers::PassManager pass_manager; compiler_options.po.always_run = true; compiler_options.po.run_fun = "f"; pass_manager.dump_all_passes(al, r1.result, compiler_options.po, diagnostics, lm); std::cerr << diagnostics.render(lm, compiler_options); } else { LCOMPILERS_ASSERT(diagnostics.has_error()) return 1; } return 0; } #ifdef HAVE_LFORTRAN_RAPIDJSON int get_symbols (const std::string &infile, const std::string &runtime_library_dir, CompilerOptions &compiler_options) { Allocator al(4*1024); LCompilers::diag::Diagnostics diagnostics; LCompilers::LocationManager lm; { LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } LCompilers::Result<:lpython::ast::ast_t> r1 = parse_python_file(al, runtime_library_dir, infile, diagnostics, 0, compiler_options.new_parser); if (r1.ok) { LCompilers::LPython::AST::ast_t* ast = r1.result; LCompilers::Result<:asr::translationunit_t> x = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); if (!x.ok) { std::cout << "{}\n"; return 0; } std::vector<:document_symbols> symbol_lists; LCompilers::document_symbols loc; for (auto &a : x.result->m_symtab->get_scope()) { std::string symbol_name = a.first; uint32_t first_line; uint32_t last_line; uint32_t first_column; uint32_t last_column; std::string filename; lm.pos_to_linecol(a.second->base.loc.first, first_line, first_column, filename); lm.pos_to_linecol(a.second->base.loc.last, last_line, last_column, filename); loc.first_column = first_column; loc.last_column = last_column; loc.first_line = first_line-1; loc.last_line = last_line-1; loc.symbol_name = symbol_name; loc.filename = filename; symbol_lists.push_back(loc); } rapidjson::Document test_output(rapidjson::kArrayType); rapidjson::Document range_object(rapidjson::kObjectType); rapidjson::Document start_detail(rapidjson::kObjectType); rapidjson::Document end_detail(rapidjson::kObjectType); rapidjson::Document location_object(rapidjson::kObjectType); rapidjson::Document test_capture(rapidjson::kObjectType); test_output.SetArray(); for (auto symbol : symbol_lists) { uint32_t start_character = symbol.first_column; uint32_t start_line = symbol.first_line; uint32_t end_character = symbol.last_column; uint32_t end_line = symbol.last_line; std::string name = symbol.symbol_name; range_object.SetObject(); rapidjson::Document::AllocatorType &allocator = range_object.GetAllocator(); start_detail.SetObject(); start_detail.AddMember("character", rapidjson::Value().SetInt(start_character), allocator); start_detail.AddMember("line", rapidjson::Value().SetInt(start_line), allocator); range_object.AddMember("start", start_detail, allocator); end_detail.SetObject(); end_detail.AddMember("character", rapidjson::Value().SetInt(end_character), allocator); end_detail.AddMember("line", rapidjson::Value().SetInt(end_line), allocator); range_object.AddMember("end", end_detail, allocator); location_object.SetObject(); location_object.AddMember("range", range_object, allocator); location_object.AddMember("uri", rapidjson::Value().SetString("uri", allocator), allocator); test_capture.SetObject(); test_capture.AddMember("kind", rapidjson::Value().SetInt(1), allocator); test_capture.AddMember("location", location_object, allocator); test_capture.AddMember("name", rapidjson::Value().SetString(name.c_str(), allocator), allocator); test_output.PushBack(test_capture, test_output.GetAllocator()); } rapidjson::StringBuffer buffer; buffer.Clear(); rapidjson::Writer<:stringbuffer> writer(buffer); test_output.Accept(writer); std::string resp_str( buffer.GetString() ); std::cout << resp_str; } else { std::cout << "{}\n"; } return 0; } int get_errors (const std::string &infile, const std::string &runtime_library_dir, CompilerOptions &compiler_options) { Allocator al(4*1024); LCompilers::diag::Diagnostics diagnostics; LCompilers::LocationManager lm; { LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } LCompilers::Result<:lpython::ast::ast_t> r1 = parse_python_file(al, runtime_library_dir, infile, diagnostics, 0, compiler_options.new_parser); if (r1.ok) { LCompilers::LPython::AST::ast_t* ast = r1.result; LCompilers::Result<:asr::translationunit_t> r = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); } std::vector<:error_highlight> diag_lists; LCompilers::error_highlight h; for (auto &d : diagnostics.diagnostics) { if (!compiler_options.show_warnings && d.level != LCompilers::diag::Level::Error) { continue; } h.message = d.message; h.severity = d.level; for (auto label : d.labels) { for (auto span : label.spans) { uint32_t first_line; uint32_t first_column; uint32_t last_line; uint32_t last_column; std::string filename; lm.pos_to_linecol(span.loc.first, first_line, first_column, filename); lm.pos_to_linecol(span.loc.last, last_line, last_column, filename); h.first_column = first_column; h.last_column = last_column; h.first_line = first_line-1; h.last_line = last_line-1; h.filename = filename; diag_lists.push_back(h); } } } rapidjson::Document range_obj(rapidjson::kObjectType); rapidjson::Document start_detail(rapidjson::kObjectType); rapidjson::Document end_detail(rapidjson::kObjectType); rapidjson::Document diag_results(rapidjson::kArrayType); rapidjson::Document diag_capture(rapidjson::kObjectType); rapidjson::Document message_send(rapidjson::kObjectType); for (auto diag : diag_lists) { uint32_t start_line = diag.first_line; uint32_t start_column = diag.first_column; uint32_t end_line = diag.last_line; uint32_t end_column = diag.last_column; uint32_t severity = diag.severity; std::string msg = diag.message; range_obj.SetObject(); rapidjson::Document::AllocatorType &allocator = range_obj.GetAllocator(); start_detail.SetObject(); start_detail.AddMember("line", rapidjson::Value().SetInt(start_line), allocator); start_detail.AddMember("character", rapidjson::Value().SetInt(start_column), allocator); range_obj.AddMember("start", start_detail, allocator); end_detail.SetObject(); end_detail.AddMember("line", rapidjson::Value().SetInt(end_line), allocator); end_detail.AddMember("character", rapidjson::Value().SetInt(end_column), allocator); range_obj.AddMember("end", end_detail, allocator); diag_results.SetArray(); diag_capture.AddMember("source", rapidjson::Value().SetString("lpyth", allocator), allocator); diag_capture.AddMember("range", range_obj, allocator); diag_capture.AddMember("message", rapidjson::Value().SetString(msg.c_str(), allocator), allocator); diag_capture.AddMember("severity", rapidjson::Value().SetInt(severity), allocator); diag_results.PushBack(diag_capture, allocator); message_send.SetObject(); message_send.AddMember("uri", rapidjson::Value().SetString("uri", allocator), allocator); message_send.AddMember("diagnostics", diag_results, allocator); } rapidjson::StringBuffer buffer; buffer.Clear(); rapidjson::Writer<:stringbuffer> writer(buffer); message_send.Accept(writer); std::string resp_str( buffer.GetString() ); std::cout << resp_str; return 0; } #endif void print_time_report(std::vector<:pair double>> &times, bool time_report) { if (time_report) { for (auto &stage :times) { std::cout << stage.first << ": " << stage.second << "ms" << std::endl; } } } #ifdef HAVE_LFORTRAN_LLVM void section(const std::string &s) { std::cout << color(LCompilers::style::bold) << color(LCompilers::fg::blue) << s << color(LCompilers::style::reset) << color(LCompilers::fg::reset) << std::endl; } int emit_llvm(const std::string &infile, const std::string &runtime_library_dir, LCompilers::PassManager& pass_manager, CompilerOptions &compiler_options) { Allocator al(4*1024); LCompilers::diag::Diagnostics diagnostics; LCompilers::LocationManager lm; { LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); std::string input = LCompilers::read_file_ok(infile); lm.init_simple(input); lm.file_ends.push_back(input.size()); } LCompilers::Result<:lpython::ast::ast_t> r = parse_python_file( al, runtime_library_dir, infile, diagnostics, 0, compiler_options.new_parser); std::cerr << diagnostics.render(lm, compiler_options); if (!r.ok) { return 1; } // Src -> AST -> ASR LCompilers::LPython::AST::ast_t* ast = r.result; diagnostics.diagnostics.clear(); LCompilers::Result<:asr::translationunit_t> r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); std::cerr << diagnostics.render(lm, compiler_options); if (!r1.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) return 2; } LCompilers::ASR::TranslationUnit_t* asr = r1.result; diagnostics.diagnostics.clear(); // ASR -> LLVM LCompilers::PythonCompiler fe(compiler_options); LCompilers::Result<:unique_ptr>> res = fe.get_llvm3(*asr, pass_manager, diagnostics, lm, infile); std::cerr << diagnostics.render(lm, compiler_options); if (!res.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) return 3; } std::cout << (res.result)->str(); return 0; } bool determine_completeness(std::string command) { auto get_last_line = [](std::string input) { if(input.length() == 1) { return input; } size_t position = input.length() - 2; while ((!(input[position] == '\n' || input[position] == '\r')) && (position > 0)) { position--; } if(input[position] == '\n' || input[position] == '\r') { position += 1; } return input.substr(position); }; std::string last_line = get_last_line(command); if ((last_line.rfind("def", 0) == 0) || (last_line.rfind("for", 0) == 0) || (last_line.rfind("if", 0) == 0) || (last_line.rfind("else", 0) == 0) || (last_line.rfind("elif", 0) == 0) || (last_line.rfind("class", 0) == 0) || (last_line.rfind('@', 0) == 0) || (last_line.rfind(' ', 0) == 0) || (last_line.rfind('\t', 0) == 0)) { return false; } return true; } int interactive_python_repl( LCompilers::PassManager& pass_manager, CompilerOptions &compiler_options, bool verbose) { Allocator al(4*1024); compiler_options.interactive = true; LCompilers::PythonCompiler fe(compiler_options); LCompilers::diag::Diagnostics diagnostics; LCompilers::LocationManager lm; std::vector<:pair double>> times; LCompilers::PythonCompiler::EvalResult r; Terminal term(true, false); std::cout << "Interactive LPython. Experimental prototype, not ready for end users." << std::endl; std::string version = LFORTRAN_VERSION; std::cout << "LPython version: " << version << std::endl; std::cout << " * Use Ctrl-D to exit" << std::endl; std::cout << " * Use Enter to submit" << std::endl; std::cout << " * Use Alt-Enter or Ctrl-N to make a new line" << std::endl; std::cout << " - Editing (Keys: Left, Right, Home, End, Backspace, Delete)" << std::endl; std::cout << " - History (Keys: Up, Down)" << std::endl; std::vector<:string> history; std::function iscomplete = determine_completeness; std::string code_string; size_t cell_count = 0; while (true) { std::string code_string = prompt0(term, ">>> ", history, iscomplete); if (code_string.size() == 1 && code_string[0] == CTRL_KEY('d')) { std::cout << std::endl; std::cout << "Exiting." << std::endl; return 0; } { cell_count++; LCompilers::LocationManager::FileLocations fl; fl.in_filename = "input"; std::ofstream out("input"); out << code_string; lm.files.push_back(fl); lm.init_simple(code_string); lm.file_ends.push_back(code_string.size()); } try { auto evaluation_start_time = std::chrono::high_resolution_clock::now(); LCompilers::Result<:pythoncompiler::evalresult> res = fe.evaluate(code_string, verbose, lm, pass_manager, diagnostics); if (res.ok) { r = res.result; std::cerr << diagnostics.render(lm, compiler_options); diagnostics.clear(); } else { LCOMPILERS_ASSERT(diagnostics.has_error()) std::cerr << diagnostics.render(lm, compiler_options); diagnostics.clear(); continue; } auto evaluation_end_time = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("evalution " + std::to_string(cell_count), std::chrono::duration (evaluation_start_time - evaluation_end_time).count())); } catch (const LCompilers::LCompilersException &e) { std::cerr << "Internal Compiler Error: Unhandled exception" << std::endl; std::vector<:stacktraceitem> d = e.stacktrace_addresses(); get_local_addresses(d); get_local_info(d); std::cerr << stacktrace2str(d, LCompilers::stacktrace_depth); std::cerr << e.name() + ": " << e.msg() << std::endl; continue; } if (verbose) { section("AST:"); std::cout << r.ast << std::endl; section("ASR:"); std::cout << r.asr << std::endl; section("LLVM IR:"); std::cout << r.llvm_ir << std::endl; } switch (r.type) { case (LCompilers::PythonCompiler::EvalResult::integer1) : { if (verbose) std::cout << "Return type: i8" << std::endl; if (verbose) section("Result:"); std::cout << r.i32 << std::endl; break; } case (LCompilers::PythonCompiler::EvalResult::integer2) : { if (verbose) std::cout << "Return type: i16" << std::endl; if (verbose) section("Result:"); std::cout << r.i64 << std::endl; break; } case (LCompilers::PythonCompiler::EvalResult::integer4) : { if (verbose) std::cout << "Return type: i32" << std::endl; if (verbose) section("Result:"); std::cout << r.i32 << std::endl; break; } case (LCompilers::PythonCompiler::EvalResult::integer8) : { if (verbose) std::cout << "Return type: i64" << std::endl; if (verbose) section("Result:"); std::cout << r.i64 << std::endl; break; } case (LCompilers::PythonCompiler::EvalResult::unsignedInteger1) : { if (verbose) std::cout << "Return type: u8" << std::endl; if (verbose) section("Result:"); std::cout << r.u32 << std::endl; break; } case (LCompilers::PythonCompiler::EvalResult::unsignedInteger2) : { if (verbose) std::cout << "Return type: u16" << std::endl; if (verbose) section("Result:"); std::cout << r.u64 << std::endl; break; } case (LCompilers::PythonCompiler::EvalResult::unsignedInteger4) : { if (verbose) std::cout << "Return type: u32" << std::endl; if (verbose) section("Result:"); std::cout << r.u32 << std::endl; break; } case (LCompilers::PythonCompiler::EvalResult::unsignedInteger8) : { if (verbose) std::cout << "Return type: u64" << std::endl; if (verbose) section("Result:"); std::cout << r.u64 << std::endl; break; } case (LCompilers::PythonCompiler::EvalResult::real4) : { if (verbose) std::cout << "Return type: f32" << std::endl; if (verbose) section("Result:"); std::cout << std::setprecision(8) << r.f32 << std::endl; break; } case (LCompilers::PythonCompiler::EvalResult::real8) : { if (verbose) std::cout << "Return type: f64" << std::endl; if (verbose) section("Result:"); std::cout << std::setprecision(17) << r.f64 << std::endl; break; } case (LCompilers::PythonCompiler::EvalResult::complex4) : { if (verbose) std::cout << "Return type: c32" << std::endl; if (verbose) section("Result:"); std::cout << std::setprecision(8) << "(" << r.c32.re << ", " << r.c32.im << ")" << std::endl; break; } case (LCompilers::PythonCompiler::EvalResult::complex8) : { if (verbose) std::cout << "Return type: c64" << std::endl; if (verbose) section("Result:"); std::cout << std::setprecision(17) << "(" << r.c64.re << ", " << r.c64.im << ")" << std::endl; break; } case (LCompilers::PythonCompiler::EvalResult::boolean) : { if (verbose) std::cout << "Return type: logical" << std::endl; if (verbose) section("Result:"); std::cout << (r.b ? "True" : "False") << std::endl; break; } case (LCompilers::PythonCompiler::EvalResult::string) : { if (verbose) std::cout << "Return type: str" << std::endl; if (verbose) section("Result:"); std::cout << (r.str == nullptr ? "" : r.str) << std::endl; break; } case (LCompilers::PythonCompiler::EvalResult::statement) : { if (verbose) { std::cout << "Return type: none" << std::endl; section("Result:"); std::cout << "(statement)" << std::endl; } break; } case (LCompilers::PythonCompiler::EvalResult::struct_type) : { if (verbose) { std::cout << "Return type: " << LCompilers::ASRUtils::get_type_code(r.structure.ttype) << std::endl; } if (verbose) section("Result:"); std::cout << fe.aggregate_type_to_string(r) << std::endl; break; } case (LCompilers::PythonCompiler::EvalResult::none) : { if (verbose) { std::cout << "Return type: none" << std::endl; section("Result:"); std::cout << "(nothing to execute)" << std::endl; } break; } default : throw LCompilers::LCompilersException("Return type not supported"); } } return 0; } /* Compiles python to object file, if `to_jit` is false otherwise execute python code using llvm JIT */ int compile_python_using_llvm( const std::string &infile, const std::string &outfile, const std::string &runtime_library_dir, LCompilers::PassManager& pass_manager, CompilerOptions &compiler_options, bool time_report, bool arg_c=false, bool to_jit=false) { Allocator al(4*1024); LCompilers::diag::Diagnostics diagnostics; LCompilers::LocationManager lm; std::vector<:pair double>>times; { LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); auto file_reading_start = std::chrono::high_resolution_clock::now(); std::string input = LCompilers::read_file_ok(infile); auto file_reading_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("File reading", std::chrono::duration (file_reading_end - file_reading_start).count())); lm.init_simple(input); lm.file_ends.push_back(input.size()); } auto parsing_start = std::chrono::high_resolution_clock::now(); LCompilers::Result<:lpython::ast::ast_t> r = parse_python_file( al, runtime_library_dir, infile, diagnostics, 0, compiler_options.new_parser); auto parsing_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("Parsing", std::chrono::duration(parsing_end - parsing_start).count())); std::cerr << diagnostics.render(lm, compiler_options); if (!r.ok) { print_time_report(times, time_report); return 1; } // Src -> AST -> ASR LCompilers::LPython::AST::ast_t* ast = r.result; diagnostics.diagnostics.clear(); auto ast_to_asr_start = std::chrono::high_resolution_clock::now(); LCompilers::Result<:asr::translationunit_t> r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, !(arg_c && compiler_options.po.disable_main), "__main__", infile); auto ast_to_asr_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("AST to ASR", std::chrono::duration(ast_to_asr_end - ast_to_asr_start).count())); std::cerr << diagnostics.render(lm, compiler_options); if (!r1.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) print_time_report(times, time_report); return 2; } LCompilers::ASR::TranslationUnit_t* asr = r1.result; if( compiler_options.po.disable_main ) { int err = LCompilers::LPython::save_pyc_files(*asr, infile, lm); if( err ) { return err; } } diagnostics.diagnostics.clear(); // ASR -> LLVM if (compiler_options.emit_debug_info) { #ifndef HAVE_RUNTIME_STACKTRACE diagnostics.add(LCompilers::diag::Diagnostic( "The `runtime stacktrace` is not enabled. To get the stacktraces, " "re-build LPython with `-DWITH_RUNTIME_STACKTRACE=yes`", LCompilers::diag::Level::Error, LCompilers::diag::Stage::Semantic, {}) ); std::cerr << diagnostics.render(lm, compiler_options); return 1; #endif } LCompilers::PythonCompiler fe(compiler_options); LCompilers::LLVMEvaluator e(compiler_options.target); auto asr_to_llvm_start = std::chrono::high_resolution_clock::now(); LCompilers::Result<:unique_ptr>> res = fe.get_llvm3(*asr, pass_manager, diagnostics, lm, infile); auto asr_to_llvm_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("ASR to LLVM", std::chrono::duration(asr_to_llvm_end - asr_to_llvm_start).count())); std::cerr << diagnostics.render(lm, compiler_options); if (!res.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) print_time_report(times, time_report); return 3; } std::unique_ptr<:llvmmodule> m = std::move(res.result); if (to_jit) { LCompilers::LPython::DynamicLibrary cpython_lib; LCompilers::LPython::DynamicLibrary symengine_lib; if (compiler_options.po.enable_cpython) { LCompilers::LPython::open_cpython_library(cpython_lib); } if (compiler_options.enable_symengine) { LCompilers::LPython::open_symengine_library(symengine_lib); } auto llvm_start = std::chrono::high_resolution_clock::now(); bool call_stmts = false; if (m->get_return_type("__module___main_____main__global_stmts") == "void") { call_stmts = true; } e.add_module(std::move(m)); if (call_stmts) { e.execfn("__module___main_____main__global_stmts"); } if (compiler_options.po.enable_cpython) { LCompilers::LPython::close_cpython_library(cpython_lib); } if (compiler_options.enable_symengine) { LCompilers::LPython::close_symengine_library(symengine_lib); } auto llvm_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("LLVM JIT execution", std::chrono::duration(llvm_end - llvm_start).count())); print_time_report(times, time_report); } else { auto llvm_start = std::chrono::high_resolution_clock::now(); e.save_object_file(*(m->m_m), outfile); auto llvm_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("LLVM to binary", std::chrono::duration(llvm_end - llvm_start).count())); print_time_report(times, time_report); } return 0; } #endif void do_print_rtl_header_dir() { std::string rtl_header_dir = LCompilers::LPython::get_runtime_library_header_dir(); std::cout << rtl_header_dir << std::endl; } void do_print_rtl_dir() { std::string rtl_dir = LCompilers::LPython::get_runtime_library_dir(); std::cout << rtl_dir << std::endl; } int compile_to_binary_wasm( const std::string &infile, const std::string &outfile, const std::string &runtime_library_dir, CompilerOptions &compiler_options, bool time_report) { Allocator al(4*1024); LCompilers::diag::Diagnostics diagnostics; LCompilers::LocationManager lm; std::vector<:pair double>>times; { LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); auto file_reading_start = std::chrono::high_resolution_clock::now(); std::string input = LCompilers::read_file_ok(infile); auto file_reading_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("File reading", std::chrono::duration (file_reading_end - file_reading_start).count())); lm.init_simple(input); lm.file_ends.push_back(input.size()); } auto parsing_start = std::chrono::high_resolution_clock::now(); LCompilers::Result<:lpython::ast::ast_t> r = parse_python_file( al, runtime_library_dir, infile, diagnostics, 0, compiler_options.new_parser); auto parsing_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("Parsing", std::chrono::duration(parsing_end - parsing_start).count())); std::cerr << diagnostics.render(lm, compiler_options); if (!r.ok) { print_time_report(times, time_report); return 1; } // Src -> AST -> ASR LCompilers::LPython::AST::ast_t* ast = r.result; diagnostics.diagnostics.clear(); auto ast_to_asr_start = std::chrono::high_resolution_clock::now(); LCompilers::Result<:asr::translationunit_t> r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); auto ast_to_asr_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("AST to ASR", std::chrono::duration(ast_to_asr_end - ast_to_asr_start).count())); std::cerr << diagnostics.render(lm, compiler_options); if (!r1.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) print_time_report(times, time_report); return 2; } LCompilers::ASR::TranslationUnit_t* asr = r1.result; if( compiler_options.po.disable_main ) { int err = LCompilers::LPython::save_pyc_files(*asr, infile, lm); if( err ) { return err; } } diagnostics.diagnostics.clear(); // ASR -> WASM auto asr_to_wasm_start = std::chrono::high_resolution_clock::now(); LCompilers::Result res = LCompilers::asr_to_wasm(*asr, al, outfile, time_report, diagnostics, compiler_options); auto asr_to_wasm_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("ASR to WASM", std::chrono::duration(asr_to_wasm_end - asr_to_wasm_start).count())); std::cerr << diagnostics.render(lm, compiler_options); print_time_report(times, time_report); if (!res.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) return 3; } return 0; } int compile_to_binary_x86( const std::string &infile, const std::string &outfile, const std::string &runtime_library_dir, CompilerOptions &compiler_options, bool time_report) { Allocator al(4*1024); LCompilers::diag::Diagnostics diagnostics; LCompilers::LocationManager lm; std::vector<:pair double>>times; { LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); auto file_reading_start = std::chrono::high_resolution_clock::now(); std::string input = LCompilers::read_file_ok(infile); auto file_reading_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("File reading", std::chrono::duration (file_reading_end - file_reading_start).count())); lm.init_simple(input); lm.file_ends.push_back(input.size()); } auto parsing_start = std::chrono::high_resolution_clock::now(); LCompilers::Result<:lpython::ast::ast_t> r = parse_python_file( al, runtime_library_dir, infile, diagnostics, 0, compiler_options.new_parser); auto parsing_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("Parsing", std::chrono::duration(parsing_end - parsing_start).count())); std::cerr << diagnostics.render(lm, compiler_options); if (!r.ok) { print_time_report(times, time_report); return 1; } // Src -> AST -> ASR LCompilers::LPython::AST::ast_t* ast = r.result; diagnostics.diagnostics.clear(); auto ast_to_asr_start = std::chrono::high_resolution_clock::now(); LCompilers::Result<:asr::translationunit_t> r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); auto ast_to_asr_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("AST to ASR", std::chrono::duration(ast_to_asr_end - ast_to_asr_start).count())); std::cerr << diagnostics.render(lm, compiler_options); if (!r1.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) print_time_report(times, time_report); return 2; } LCompilers::ASR::TranslationUnit_t* asr = r1.result; if( compiler_options.po.disable_main ) { int err = LCompilers::LPython::save_pyc_files(*asr, infile, lm); if( err ) { return err; } } diagnostics.diagnostics.clear(); // ASR -> X86 auto asr_to_x86_start = std::chrono::high_resolution_clock::now(); LCompilers::Result r3 = LCompilers::asr_to_x86(*asr, al, outfile, time_report, diagnostics); auto asr_to_x86_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("ASR to X86", std::chrono::duration(asr_to_x86_end - asr_to_x86_start).count())); std::cerr << diagnostics.render(lm, compiler_options); print_time_report(times, time_report); if (!r3.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) return 3; } return 0; } int compile_to_binary_wasm_to_x86( const std::string &infile, const std::string &outfile, const std::string &runtime_library_dir, CompilerOptions &compiler_options, bool time_report, Backend backend) { Allocator al(4*1024); LCompilers::diag::Diagnostics diagnostics; LCompilers::LocationManager lm; std::vector<:pair double>>times; { LCompilers::LocationManager::FileLocations fl; fl.in_filename = infile; lm.files.push_back(fl); auto file_reading_start = std::chrono::high_resolution_clock::now(); std::string input = LCompilers::read_file_ok(infile); auto file_reading_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("File reading", std::chrono::duration (file_reading_end - file_reading_start).count())); lm.init_simple(input); lm.file_ends.push_back(input.size()); } auto parsing_start = std::chrono::high_resolution_clock::now(); LCompilers::Result<:lpython::ast::ast_t> r = parse_python_file( al, runtime_library_dir, infile, diagnostics, 0, compiler_options.new_parser); auto parsing_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("Parsing", std::chrono::duration(parsing_end - parsing_start).count())); std::cerr << diagnostics.render(lm, compiler_options); if (!r.ok) { print_time_report(times, time_report); return 1; } // Src -> AST -> ASR LCompilers::LPython::AST::ast_t* ast = r.result; diagnostics.diagnostics.clear(); auto ast_to_asr_start = std::chrono::high_resolution_clock::now(); LCompilers::Result<:asr::translationunit_t> r1 = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *ast, diagnostics, compiler_options, true, "__main__", infile); auto ast_to_asr_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("AST to ASR", std::chrono::duration(ast_to_asr_end - ast_to_asr_start).count())); std::cerr << diagnostics.render(lm, compiler_options); if (!r1.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) print_time_report(times, time_report); return 2; } LCompilers::ASR::TranslationUnit_t* asr = r1.result; if( compiler_options.po.disable_main ) { int err = LCompilers::LPython::save_pyc_files(*asr, infile, lm); if( err ) { return err; } } diagnostics.diagnostics.clear(); // ASR -> WASM auto asr_to_wasm_start = std::chrono::high_resolution_clock::now(); LCompilers::Result<:vec>> r3 = LCompilers::asr_to_wasm_bytes_stream(*asr, al, diagnostics, compiler_options); auto asr_to_wasm_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("ASR to WASM", std::chrono::duration(asr_to_wasm_end - asr_to_wasm_start).count())); std::cerr << diagnostics.render(lm, compiler_options); if (!r3.ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) print_time_report(times, time_report); return 3; } bool is_result_ok; if (backend == Backend::wasm_x86) { // WASM -> X86 auto wasm_to_x86_start = std::chrono::high_resolution_clock::now(); LCompilers::Result res = LCompilers::wasm_to_x86(r3.result, al, outfile, time_report, diagnostics); auto wasm_to_x86_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("WASM to X86", std::chrono::duration(wasm_to_x86_end - wasm_to_x86_start).count())); is_result_ok = res.ok; } else { // WASM -> X64 auto wasm_to_x64_start = std::chrono::high_resolution_clock::now(); LCompilers::Result res = LCompilers::wasm_to_x64(r3.result, al, outfile, time_report, diagnostics); auto wasm_to_x64_end = std::chrono::high_resolution_clock::now(); times.push_back(std::make_pair("WASM to X64", std::chrono::duration(wasm_to_x64_end - wasm_to_x64_start).count())); is_result_ok = res.ok; } std::cerr << diagnostics.render(lm, compiler_options); print_time_report(times, time_report); if (!is_result_ok) { LCOMPILERS_ASSERT(diagnostics.has_error()) return 4; } return 0; } // infile is an object file // outfile will become the executable int link_executable(const std::vector<:string> &infiles, const std::string &outfile, const std::string &runtime_library_dir, Backend backend, bool static_executable, bool kokkos, CompilerOptions &compiler_options, const std::string &rtlib_header_dir) { /* The `gcc` line for dynamic linking that is constructed below: gcc -o $outfile $infile \ -Lsrc/runtime -Wl,-rpath=src/runtime -llpython_runtime is equivalent to the following: ld -o $outfile $infile \ -Lsrc/runtime -rpath=src/runtime -llpython_runtime \ -dynamic-linker /lib64/ld-linux-x86-64.so.2 \ /usr/lib/x86_64-linux-gnu/Scrt1.o /usr/lib/x86_64-linux-gnu/libc.so and this for static linking: gcc -static -o $outfile $infile \ -Lsrc/runtime -Wl,-rpath=src/runtime -llpython_runtime_static is equivalent to: ld -o $outfile $infile \ -Lsrc/runtime -rpath=src/runtime -llpython_runtime_static \ /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o \ /usr/lib/x86_64-linux-gnu/libc.a \ /usr/lib/gcc/x86_64-linux-gnu/7/libgcc_eh.a \ /usr/lib/x86_64-linux-gnu/libc.a \ /usr/lib/gcc/x86_64-linux-gnu/7/libgcc.a \ /usr/lib/x86_64-linux-gnu/crtn.o This was tested on Ubuntu 18.04. The `gcc` and `ld` approaches are equivalent except: 1. The `gcc` command knows how to find and link the `libc` library, while in `ld` we must do that manually 2. For dynamic linking, we must also specify the dynamic linker for `ld` Notes: * We can use `lld` to do the linking via the `ld` approach, so `ld` is preferable if we can mitigate the issues 1. and 2. * If we ship our own libc (such as musl), then we know how to find it and link it, which mitigates the issue 1. * If we link `musl` statically, then issue 2. does not apply. * If we link `musl` dynamically, then we have to find the dynamic linker (doable), which mitigates the issue 2. One way to find the default dynamic linker is by: $ readelf -e /bin/bash | grep ld-linux [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] There are probably simpler ways. */ #ifdef HAVE_LFORTRAN_LLVM std::string t = (compiler_options.target == "") ? LCompilers::LLVMEvaluator::get_default_target_triple() : compiler_options.target; #else std::string t = (compiler_options.platform == LCompilers::Platform::Windows) ? "x86_64-pc-windows-msvc" : compiler_options.target; #endif if (backend == Backend::llvm) { if (t == "x86_64-pc-windows-msvc") { std::string cmd = "link /NOLOGO /OUT:" + outfile + " "; for (auto &s : infiles) { cmd += s + " "; } cmd += runtime_library_dir + "\\lpython_runtime_static.lib > NUL"; int err = system(cmd.c_str()); if (err) { std::cout << "The command '" + cmd + "' failed." << std::endl; return 10; } } else { std::string CC = "cc"; char *env_CC = std::getenv("LFORTRAN_CC"); if (env_CC) CC = env_CC; std::string base_path = "\"" + runtime_library_dir + "\""; std::string options; std::string runtime_lib = "lpython_runtime"; if (static_executable) { if (compiler_options.platform != LCompilers::Platform::macOS_Intel && compiler_options.platform != LCompilers::Platform::macOS_ARM) { options += " -static "; } runtime_lib = "lpython_runtime_static"; } std::string cmd = CC + options + " -o " + outfile + " "; for (auto &s : infiles) { cmd += s + " "; } if (compiler_options.enable_symengine) { cmd += " -I${CONDA_PREFIX}/include"; } cmd += + " -L" + base_path + " -Wl,-rpath," + base_path + " -l" + runtime_lib + " -lm"; if (compiler_options.enable_symengine) { cmd += " -L$CONDA_PREFIX/lib -Wl,-rpath -Wl,$CONDA_PREFIX/lib -lsymengine"; } if (compiler_options.po.enable_cpython) { std::string py_version = "3.10"; std::string py_flags = R"(-I $CONDA_PREFIX/include/python)" + py_version + R"( -L$CONDA_PREFIX/lib -Wl,-rpath -Wl,$CONDA_PREFIX/lib -lpython)" + py_version + R"()"; if (compiler_options.link_numpy) { py_flags += R"( -I$CONDA_PREFIX/lib/python)" + py_version + R"(/site-packages/numpy/core/include)"; } cmd += " " + py_flags; } int err = system(cmd.c_str()); if (err) { std::cout << "The command '" + cmd + "' failed." << std::endl; return 10; } } return 0; } else if (backend == Backend::cpp) { std::string CXX = "g++"; std::string options, post_options; if (static_executable) { options += " -static "; } if (compiler_options.openmp) { options += " -fopenmp "; } if (kokkos) { std::string kokkos_dir = get_kokkos_dir(); post_options += kokkos_dir + "/lib/libkokkoscontainers.a " + kokkos_dir + "/lib/libkokkoscore.a -ldl"; } std::string cmd = CXX + options + " -o " + outfile + " "; for (auto &s : infiles) { cmd += s + " "; } cmd += " -L"; cmd += " " + post_options + " -lm"; int err = system(cmd.c_str()); if (err) { std::cout << "The command '" + cmd + "' failed." << std::endl; return 10; } return 0; } else if (backend == Backend::c) { std::string CXX = "gcc"; std::string cmd = CXX + " -o " + outfile + " "; std::string base_path = "\"" + runtime_library_dir + "\""; std::string runtime_lib = "lpython_runtime"; for (auto &s : infiles) { cmd += s + " "; } cmd += " -I " + rtlib_header_dir; if (compiler_options.enable_symengine) { cmd += " -I${CONDA_PREFIX}/include"; } cmd += " -L" + base_path + " -Wl,-rpath," + base_path + " -l" + runtime_lib + " -lm"; if (compiler_options.enable_symengine) { cmd += " -L$CONDA_PREFIX/lib -Wl,-rpath -Wl,$CONDA_PREFIX/lib -lsymengine"; } if (compiler_options.po.enable_cpython) { std::string py_version = "3.10"; std::string py_flags = R"(-I $CONDA_PREFIX/include/python)" + py_version + R"( -L$CONDA_PREFIX/lib -Wl,-rpath -Wl,$CONDA_PREFIX/lib -lpython)" + py_version + R"()"; if (compiler_options.link_numpy) { py_flags += R"( -I$CONDA_PREFIX/lib/python)" + py_version + R"(/site-packages/numpy/core/include)"; } cmd += " " + py_flags; } int err = system(cmd.c_str()); if (err) { std::cout << "The command '" + cmd + "' failed." << std::endl; return 10; } return 0; } else if (backend == Backend::x86) { std::string cmd = "cp " + infiles[0] + " " + outfile; int err = system(cmd.c_str()); if (err) { std::cout << "The command '" + cmd + "' failed." << std::endl; return 10; } return 0; } else { LCOMPILERS_ASSERT(false); return 1; } } // int emit_c_preprocessor(const std::string &infile, CompilerOptions &compiler_options) // { // std::string input = read_file_ok(infile); // // LFortran::CPreprocessor cpp(compiler_options); // LFortran::LocationManager lm; // lm.in_filename = infile; // std::string s = cpp.run(input, lm, cpp.macro_definitions); // std::cout << s; // return 0; // } } // anonymous namespace #ifdef HAVE_BUILD_TO_WASM namespace wasm { #define INITIALIZE_VARS CompilerOptions compiler_options; \ compiler_options.use_colors = true; \ compiler_options.indent = true; \ Allocator al(4*1024); \ LCompilers::diag::Diagnostics diagnostics; \ LCompilers::LocationManager lm; \ { \ LCompilers::LocationManager::FileLocations fl; \ fl.in_filename = "input.txt"; \ std::ofstream out("input.txt"); \ out << input; \ lm.files.push_back(fl); \ lm.init_simple(std::string(input)); \ lm.file_ends.push_back(strlen(input)); \ } std::string out; extern "C" { // using extern "C" to prevent function name mangling EMSCRIPTEN_KEEPALIVE char* emit_ast_from_source(char *input) { INITIALIZE_VARS; lm.init_simple(input); LCompilers::Result<:lpython::ast::module_t> ast = LCompilers::LPython::parse(al, input, 0, diagnostics); out = diagnostics.render(lm, compiler_options); if (ast.ok) { auto casted_ast = (LCompilers::LPython::AST::ast_t*)ast.result; out += LCompilers::LPython::pickle_python(*casted_ast, compiler_options.use_colors, compiler_options.indent); } return &out[0]; } EMSCRIPTEN_KEEPALIVE char* emit_asr_from_source(char *input) { INITIALIZE_VARS; lm.init_simple(input); LCompilers::Result<:lpython::ast::module_t> ast = LCompilers::LPython::parse(al, input, 0, diagnostics); out = diagnostics.render(lm, compiler_options); if (ast.ok) { auto casted_ast = (LCompilers::LPython::AST::ast_t*)ast.result; LCompilers::Result<:asr::translationunit_t> asr = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *casted_ast, diagnostics, compiler_options, true, "__main__", "input"); out = diagnostics.render(lm, compiler_options); if (asr.ok) { out += LCompilers::pickle(*asr.result, compiler_options.use_colors, compiler_options.indent, false /* with_intrinsic_modules */); } } return &out[0]; } EMSCRIPTEN_KEEPALIVE char* emit_wat_from_source(char *input) { INITIALIZE_VARS; lm.init_simple(input); LCompilers::Result<:lpython::ast::module_t> ast = LCompilers::LPython::parse(al, input, 0, diagnostics); out = diagnostics.render(lm, compiler_options); if (ast.ok) { auto casted_ast = (LCompilers::LPython::AST::ast_t*)ast.result; LCompilers::Result<:asr::translationunit_t> asr = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *casted_ast, diagnostics, compiler_options, true, "__main__", "input"); out = diagnostics.render(lm, compiler_options); if (asr.ok) { LCompilers::Result<:vec>> wasm = LCompilers::asr_to_wasm_bytes_stream(*asr.result, al, diagnostics, compiler_options); out = diagnostics.render(lm, compiler_options); if (wasm.ok) { LCompilers::Result<:string> wat = LCompilers::wasm_to_wat(wasm.result, al, diagnostics); out = diagnostics.render(lm, compiler_options); if (wat.ok) { out += wat.result; } } } } return &out[0]; } EMSCRIPTEN_KEEPALIVE char* emit_cpp_from_source(char *input) { INITIALIZE_VARS; lm.init_simple(input); LCompilers::Result<:lpython::ast::module_t> ast = LCompilers::LPython::parse(al, input, 0, diagnostics); out = diagnostics.render(lm, compiler_options); if (ast.ok) { auto casted_ast = (LCompilers::LPython::AST::ast_t*)ast.result; LCompilers::Result<:asr::translationunit_t> asr = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *casted_ast, diagnostics, compiler_options, true, "__main__", "input"); out = diagnostics.render(lm, compiler_options); if (asr.ok) { auto res = LCompilers::asr_to_cpp(al, *asr.result, diagnostics, compiler_options, 0); out = diagnostics.render(lm, compiler_options); if (res.ok) { out += res.result; } } } return &out[0]; } // EMSCRIPTEN_KEEPALIVE char* emit_c_from_source(char *input) { // INITIALIZE_VARS; // LCompilers::Result<:string> r = fe.get_c(input, lm, diagnostics, 1); // out = diagnostics.render(lm, compiler_options); // if (r.ok) { out += r.result; } // return &out[0]; // } // EMSCRIPTEN_KEEPALIVE char* emit_py_from_source(char *input) { // INITIALIZE_VARS; // LCompilers::Result<:string> r = fe.get_py(input, lm, diagnostics); // out = diagnostics.render(lm, compiler_options); // if (r.ok) { out += r.result; } // return &out[0]; // } EMSCRIPTEN_KEEPALIVE char* emit_wasm_from_source(char *input) { INITIALIZE_VARS; lm.init_simple(input); LCompilers::Result<:lpython::ast::module_t> ast = LCompilers::LPython::parse(al, input, 0, diagnostics); out = diagnostics.render(lm, compiler_options); if (ast.ok) { auto casted_ast = (LCompilers::LPython::AST::ast_t*)ast.result; LCompilers::Result<:asr::translationunit_t> asr = LCompilers::LPython::python_ast_to_asr(al, lm, nullptr, *casted_ast, diagnostics, compiler_options, true, "__main__", "input"); out = diagnostics.render(lm, compiler_options); if (asr.ok) { LCompilers::Result<:vec>> wasm = LCompilers::asr_to_wasm_bytes_stream(*asr.result, al, diagnostics, compiler_options); out = diagnostics.render(lm, compiler_options); if (wasm.ok) { out = "0"; // exit code for (size_t i = 0; i < wasm.result.size(); i++) { out += "," + std::to_string(wasm.result[i]); } return &out[0]; } } } out = "1"; // non-zero exit code out += "," + diagnostics.render(lm, compiler_options); return &out[0]; } } } // namespace wasm #endif int main(int argc, char *argv[]) { LCompilers::initialize(); #if defined(HAVE_LFORTRAN_STACKTRACE) LCompilers::print_stack_on_segfault(); #endif try { int dirname_length; LCompilers::LPython::get_executable_path(LCompilers::binary_executable_path, dirname_length); std::string runtime_library_dir = LCompilers::LPython::get_runtime_library_dir(); std::string rtlib_header_dir = LCompilers::LPython::get_runtime_library_header_dir(); Backend backend; bool arg_S = false; bool arg_c = false; bool arg_v = false; // bool arg_E = false; // std::string arg_J; // std::vector<:string> arg_I; // std::vector<:string> arg_l; // std::vector<:string> arg_L; std::vector<:string> arg_files; bool arg_version = false; bool show_tokens = false; bool show_ast = false; bool show_asr = false; bool show_cpp = false; bool show_c = false; bool show_python = false; bool show_document_symbols = false; bool show_errors = false; bool with_intrinsic_modules = false; std::string arg_pass; std::string skip_pass; bool arg_no_color = false; bool arg_no_indent = false; bool show_llvm = false; bool show_asm = false; bool show_wat = false; bool time_report = false; bool static_link = false; std::string arg_backend = "llvm"; std::string arg_kernel_f; bool print_targets = false; bool print_rtl_header_dir = false; bool print_rtl_dir = false; bool separate_compilation = false; bool to_jit = false; bool disable_warnings = false; bool hide_error_banner = false; std::string arg_fmt_file; // int arg_fmt_indent = 4; // bool arg_fmt_indent_unit = false; // bool arg_fmt_inplace = false; // bool arg_fmt_no_color = false; std::string arg_mod_file; // bool arg_mod_show_asr = false; // bool arg_mod_no_color = false; std::string arg_pywrap_file; std::string arg_pywrap_array_order="f"; CompilerOptions compiler_options; LCompilers::PassManager lpython_pass_manager; CLI::App app{"LPython: modern interactive LLVM-based Python compiler"}; // Standard options compatible with gfortran, gcc or clang // We follow the established conventions app.add_option("files", arg_files, "Source files"); // Should the following Options required for LPython?? // Instead we need support all the options from Python 3 app.add_flag("-S", arg_S, "Emit assembly, do not assemble or link"); app.add_flag("-c", arg_c, "Compile and assemble, do not link"); app.add_option("-o", compiler_options.arg_o, "Specify the file to place the output into"); app.add_flag("-v", arg_v, "Be more verbose"); // app.add_flag("-E", arg_E, "Preprocess only; do not compile, assemble or link"); // app.add_option("-l", arg_l, "Link library option"); // app.add_option("-L", arg_L, "Library path option"); app.add_option("-I", compiler_options.import_paths, "Specify the paths" "to look for the module")->allow_extra_args(false); // app.add_option("-J", arg_J, "Where to save mod files"); app.add_flag("--jit", to_jit, "Execute the program using just-in-time (JIT) compiler"); app.add_flag("-g", compiler_options.emit_debug_info, "Compile with debugging information"); app.add_flag("--debug-with-line-column", compiler_options.emit_debug_line_column, "Convert the linear location info into line + column in the debugging information"); // app.add_option("-D", compiler_options.c_preprocessor_defines, "Define = (or 1 if omitted)")->allow_extra_args(false); app.add_flag("--version", arg_version, "Display compiler version information"); // LPython specific options app.add_flag("--cpp", compiler_options.c_preprocessor, "Enable C preprocessing"); app.add_flag("--show-tokens", show_tokens, "Show tokens for the given python file and exit"); app.add_flag("--new-parser", compiler_options.new_parser, "Use the new LPython parser"); app.add_flag("--show-ast", show_ast, "Show AST for the given python file and exit"); app.add_flag("--show-asr", show_asr, "Show ASR for the given python file and exit"); app.add_flag("--show-llvm", show_llvm, "Show LLVM IR for the given file and exit"); app.add_flag("--show-cpp", show_cpp, "Show C++ translation source for the given python file and exit"); app.add_flag("--show-c", show_c, "Show C translation source for the given python file and exit"); app.add_flag("--show-python", show_python, "Show Python translation source for the given python file and exit"); app.add_flag("--show-asm", show_asm, "Show assembly for the given file and exit"); app.add_flag("--show-wat", show_wat, "Show WAT (WebAssembly Text Format) and exit"); app.add_flag("--show-stacktrace", compiler_options.show_stacktrace, "Show internal stacktrace on compiler errors"); app.add_flag("--with-intrinsic-mods", with_intrinsic_modules, "Show intrinsic modules in ASR"); app.add_flag("--no-color", arg_no_color, "Turn off colored AST/ASR"); app.add_flag("--no-indent", arg_no_indent, "Turn off Indented print ASR/AST"); app.add_flag("--tree", compiler_options.po.tree, "Tree structure print ASR/AST"); app.add_flag("--json", compiler_options.po.json, "Print ASR/AST Json format"); app.add_flag("--no-loc", compiler_options.po.no_loc, "Skip location information in ASR/AST Json format"); app.add_flag("--visualize", compiler_options.po.visualize, "Print ASR/AST Visualization"); app.add_option("--pass", arg_pass, "Apply the ASR pass and show ASR (implies --show-asr)"); app.add_option("--skip-pass", skip_pass, "Skip an ASR pass in default pipeline"); app.add_flag("--disable-main", compiler_options.po.disable_main, "Do not generate any code for the `main` function"); app.add_flag("--symtab-only", compiler_options.symtab_only, "Only create symbol tables in ASR (skip executable stmt)"); app.add_flag("--time-report", time_report, "Show compilation time report"); app.add_flag("--static", static_link, "Create a static executable"); app.add_flag("--no-warnings", disable_warnings, "Turn off all warnings"); app.add_flag("--no-error-banner", hide_error_banner, "Turn off error banner"); app.add_option("--backend", arg_backend, "Select a backend (llvm, cpp, x86, wasm, wasm_x86, wasm_x64)")->capture_default_str(); app.add_flag("--enable-bounds-checking", compiler_options.bounds_checking, "Turn on index bounds checking"); app.add_flag("--openmp", compiler_options.openmp, "Enable openmp"); app.add_flag("--fast", compiler_options.po.fast, "Best performance (disable strict standard compliance)"); app.add_option("--target", compiler_options.target, "Generate code for the given target")->capture_default_str(); app.add_flag("--print-targets", print_targets, "Print the registered targets"); app.add_flag("--get-rtl-header-dir", print_rtl_header_dir, "Print the path to the runtime library header file"); app.add_flag("--get-rtl-dir", print_rtl_dir, "Print the path to the runtime library file"); app.add_flag("--verbose", compiler_options.po.verbose, "Print debugging statements"); app.add_flag("--dump-all-passes", compiler_options.po.dump_all_passes, "Apply all the passes and dump the ASR into a file"); app.add_flag("--dump-all-passes-fortran", compiler_options.po.dump_fortran, "Apply all passes and dump the ASR after each pass into fortran file"); app.add_flag("--cumulative", compiler_options.po.pass_cumulative, "Apply all the passes cumulatively till the given pass"); app.add_flag("--enable-cpython", compiler_options.po.enable_cpython, "Enable CPython runtime"); app.add_flag("--enable-symengine", compiler_options.enable_symengine, "Enable Symengine runtime"); app.add_flag("--link-numpy", compiler_options.link_numpy, "Enable NumPy runtime (implies --enable-cpython)"); app.add_flag("--separate-compilation", separate_compilation, "Generates unique names for all the symbols"); app.add_flag("--module-mangling", compiler_options.po.module_name_mangling, "Mangles the module name"); app.add_flag("--global-mangling", compiler_options.po.global_symbols_mangling, "Mangles all the global symbols"); app.add_flag("--intrinsic-mangling", compiler_options.po.intrinsic_symbols_mangling, "Mangles all the intrinsic symbols"); app.add_flag("--all-mangling", compiler_options.po.all_symbols_mangling, "Mangles all possible symbols"); // LSP specific options app.add_flag("--show-errors", show_errors, "Show errors when LSP is running in the background"); app.add_flag("--show-document-symbols", show_document_symbols, "Show symbols in lpython file"); /* * Subcommands: */ // fmt: Should LPython support `fmt` subcommand?? // CLI::App &fmt = *app.add_subcommand("fmt", "Format Fortran source files."); // fmt.add_option("file", arg_fmt_file, "Fortran source file to format")->required(); // fmt.add_flag("-i", arg_fmt_inplace, "Modify in-place (instead of writing to stdout)"); // fmt.add_option("--spaces", arg_fmt_indent, "Number of spaces to use for indentation")->capture_default_str(); // fmt.add_flag("--indent-unit", arg_fmt_indent_unit, "Indent contents of sub / fn / prog / mod"); // fmt.add_flag("--no-color", arg_fmt_no_color, "Turn off color when writing to stdout"); // kernel CLI::App &kernel = *app.add_subcommand("kernel", "Run in Jupyter kernel mode."); kernel.add_option("-f", arg_kernel_f, "The kernel connection file")->required(); // mod // CLI::App &mod = *app.add_subcommand("mod", "Fortran mod file utilities."); // mod.add_option("file", arg_mod_file, "Mod file (*.mod)")->required(); // mod.add_flag("--show-asr", arg_mod_show_asr, "Show ASR for the module"); // mod.add_flag("--no-color", arg_mod_no_color, "Turn off colored ASR"); // pywrap CLI::App &pywrap = *app.add_subcommand("pywrap", "Python wrapper generator"); pywrap.add_option("file", arg_pywrap_file, "Fortran source file (*.f90)")->required(); pywrap.add_option("--array-order", arg_pywrap_array_order, "Select array order (c, f)")->capture_default_str(); app.get_formatter()->column_width(25); app.require_subcommand(0, 1); CLI11_PARSE(app, argc, argv); lcompilers_unique_ID_separate_compilation = separate_compilation ? LCompilers::get_unique_ID(): ""; if( compiler_options.po.fast && compiler_options.bounds_checking ) { // ReleaseSafe Mode } else if ( compiler_options.po.fast ) { // Release Mode // No need to do anything, compiler_options.po.fast // sends the signal to pass_manager when passes are applied // Earlier it was redundant to call `use_optimisation_passes` // which is now removed } else { // Debug Mode compiler_options.bounds_checking = true; } if (compiler_options.link_numpy) { compiler_options.po.enable_cpython = true; } if (disable_warnings) { compiler_options.show_warnings = false; } if (hide_error_banner) { compiler_options.show_error_banner = false; } if (arg_version) { std::string version = LFORTRAN_VERSION; std::cout << "LPython version: " << version << std::endl; std::cout << "Platform: " << pf2s(compiler_options.platform) << std::endl; #ifdef HAVE_LFORTRAN_LLVM std::cout << "Default target: " << LCompilers::LLVMEvaluator::get_default_target_triple() << std::endl; #endif return 0; } if (print_targets) { #ifdef HAVE_LFORTRAN_LLVM LCompilers::LLVMEvaluator::print_targets(); return 0; #else std::cerr << "The --print-targets option requires the LLVM backend to be enabled. Recompile with `WITH_LLVM=yes`." << std::endl; return 1; #endif } if (print_rtl_header_dir) { do_print_rtl_header_dir(); return 0; } if (print_rtl_dir) { do_print_rtl_dir(); return 0; } compiler_options.use_colors = !arg_no_color; compiler_options.indent = !arg_no_indent; // if (fmt) { // return format(arg_fmt_file, arg_fmt_inplace, !arg_fmt_no_color, // arg_fmt_indent, arg_fmt_indent_unit, compiler_options); // } if (kernel) { #ifdef HAVE_LFORTRAN_XEUS return LCompilers::LPython::run_kernel(arg_kernel_f); #else std::cerr << "The kernel subcommand requires LFortran to be compiled with XEUS support. Recompile with `WITH_XEUS=yes`." << std::endl; return 1; #endif } // if (mod) { // if (arg_mod_show_asr) { // Allocator al(1024*1024); // LFortran::ASR::TranslationUnit_t *asr; // asr = LFortran::mod_to_asr(al, arg_mod_file); // std::cout << LFortran::pickle(*asr, !arg_mod_no_color) << std::endl; // return 0; // } // return 0; // } if (pywrap) { std::cerr << "Pywrap is not implemented yet." << std::endl; return 1; } if (arg_backend == "llvm") { backend = Backend::llvm; } else if (arg_backend == "c") { backend = Backend::c; } else if (arg_backend == "cpp") { backend = Backend::cpp; } else if (arg_backend == "x86") { backend = Backend::x86; } else if (arg_backend == "wasm") { backend = Backend::wasm; } else if (arg_backend == "wasm_x86") { backend = Backend::wasm_x86; } else if (arg_backend == "wasm_x64") { backend = Backend::wasm_x64; } else { std::cerr << "The backend must be one of: llvm, c, cpp, x86, wasm, wasm_x86, wasm_x64." << std::endl; return 1; } if (arg_files.size() == 0) { #ifdef HAVE_LFORTRAN_LLVM lpython_pass_manager.parse_pass_arg(arg_pass, skip_pass); lpython_pass_manager.use_default_passes(); compiler_options.po.disable_main = true; compiler_options.emit_debug_line_column = false; compiler_options.separate_compilation = false; return interactive_python_repl(lpython_pass_manager, compiler_options, arg_v); #else std::cerr << "Interactive prompt requires the LLVM backend to be enabled. Recompile with `WITH_LLVM=yes`." << std::endl; return 1; #endif } // TODO: for now we ignore the other filenames, only handle // the first: std::string arg_file = arg_files[0]; if (CLI::NonexistentPath(arg_file).empty()){ std::cerr << "The input file does not exist: " << arg_file << std::endl; return 1; } std::string outfile; std::string basename; basename = remove_extension(arg_file); basename = remove_path(basename); if (compiler_options.arg_o.size() > 0) { outfile = compiler_options.arg_o; } else if (arg_S) { outfile = basename + ".s"; } else if (arg_c) { outfile = basename + ".o"; } else if (show_tokens) { outfile = basename + ".tok"; } else if (show_ast) { outfile = basename + ".ast"; } else if (show_asr) { outfile = basename + ".asr"; } else if (show_llvm) { outfile = basename + ".ll"; } else if (show_wat) { outfile = basename + ".wat"; } else { outfile = basename + ".out"; } if (compiler_options.po.dump_fortran || compiler_options.po.dump_all_passes) { dump_all_passes(arg_file, runtime_library_dir, compiler_options); } // if (arg_E) { // return emit_c_preprocessor(arg_file, compiler_options); // } lpython_pass_manager.parse_pass_arg(arg_pass, skip_pass); if (show_tokens) { return emit_tokens(arg_file, true, compiler_options); } if (show_ast) { return emit_ast(arg_file, runtime_library_dir, compiler_options); } if (show_asr) { return emit_asr(arg_file, lpython_pass_manager, runtime_library_dir, with_intrinsic_modules, compiler_options); } if (show_cpp) { return emit_cpp(arg_file, runtime_library_dir, compiler_options); } if (show_c) { compiler_options.po.c_mangling = true; return emit_c(arg_file, runtime_library_dir, lpython_pass_manager, compiler_options); } if (show_python) { return emit_python(arg_file, runtime_library_dir, compiler_options); } if (show_wat) { return emit_wat(arg_file, runtime_library_dir, compiler_options); } if (show_document_symbols) { #ifdef HAVE_LFORTRAN_RAPIDJSON return get_symbols(arg_file, runtime_library_dir, compiler_options); #else std::cerr << "Compiler was not built with LSP support (-DWITH_LSP), please build it again." << std::endl; return 1; #endif } if (show_errors) { #ifdef HAVE_LFORTRAN_RAPIDJSON return get_errors(arg_file, runtime_library_dir, compiler_options); #else std::cerr << "Compiler was not configured with LSP support (-DWITH_LSP), please build it again." << std::endl; return 1; #endif } lpython_pass_manager.use_default_passes(); if (show_llvm) { #ifdef HAVE_LFORTRAN_LLVM return emit_llvm(arg_file, runtime_library_dir, lpython_pass_manager, compiler_options); #else std::cerr << "The --show-llvm option requires the LLVM backend to be enabled. Recompile with `WITH_LLVM=yes`." << std::endl; return 1; #endif } if (show_asm) { std::cerr << "The --show-asm option is not implemented yet." << std::endl; return 1; } if (arg_S) { if (backend == Backend::llvm) { std::cerr << "The -S option is not implemented yet for the LLVM backend." << std::endl; return 1; } else if (backend == Backend::cpp) { std::cerr << "The C++ backend does not work with the -S option yet." << std::endl; return 1; } else { LCOMPILERS_ASSERT(false); } } if (arg_c && !to_jit) { if (backend == Backend::llvm) { #ifdef HAVE_LFORTRAN_LLVM return compile_python_using_llvm(arg_file, outfile, runtime_library_dir, lpython_pass_manager, compiler_options, time_report, arg_c); #else std::cerr << "The -c option requires the LLVM backend to be enabled. Recompile with `WITH_LLVM=yes`." << std::endl; return 1; #endif } else { throw LCompilers::LCompilersException("Unsupported backend."); } } if (endswith(arg_file, ".py")) { int err = 0; if (to_jit) { #ifdef HAVE_LFORTRAN_LLVM if (backend != Backend::llvm) { std::cerr << "JIT option is only available with LLVM backend" << std::endl; return 1; } compiler_options.emit_debug_info = false; compiler_options.emit_debug_line_column = false; compiler_options.separate_compilation = false; return compile_python_using_llvm(arg_file, "", runtime_library_dir, lpython_pass_manager, compiler_options, time_report, false, true); #else std::cerr << "Just-In-Time Compilation of Python files requires the LLVM backend to be enabled." " Recompile with `WITH_LLVM=yes`." << std::endl; return 1; #endif } if (backend == Backend::x86) { err = compile_to_binary_x86(arg_file, outfile, runtime_library_dir, compiler_options, time_report); } else if (backend == Backend::wasm) { err = compile_to_binary_wasm(arg_file, outfile, runtime_library_dir, compiler_options, time_report); } else if (backend == Backend::wasm_x86 || backend == Backend::wasm_x64) { err = compile_to_binary_wasm_to_x86(arg_file, outfile, runtime_library_dir, compiler_options, time_report, backend); } else if (backend == Backend::c) { compiler_options.po.c_mangling = true; std::string emit_file_name = basename + "__tmp__generated__.c"; err = emit_c_to_file(arg_file, emit_file_name, runtime_library_dir, lpython_pass_manager, compiler_options); if (err != 0) return err; err = link_executable({emit_file_name}, outfile, runtime_library_dir, backend, static_link, true, compiler_options, rtlib_header_dir); } else if (backend == Backend::llvm) { #ifdef HAVE_LFORTRAN_LLVM std::string tmp_o = outfile + ".tmp.o"; err = compile_python_using_llvm(arg_file, tmp_o, runtime_library_dir, lpython_pass_manager, compiler_options, time_report); if (err != 0) return err; err = link_executable({tmp_o}, outfile, runtime_library_dir, backend, static_link, true, compiler_options, rtlib_header_dir); #ifdef HAVE_RUNTIME_STACKTRACE if (compiler_options.emit_debug_info) { // TODO: Replace the following hardcoded part std::string cmd = ""; #ifdef HAVE_LFORTRAN_MACHO cmd += "dsymutil " + basename + ".out && llvm-dwarfdump --debug-line " + basename + ".out.dSYM > "; #else cmd += "llvm-dwarfdump --debug-line " + basename + ".out > "; #endif cmd += basename + "_ldd.txt && (cd libasr/src/libasr; ./dwarf_convert.py ../../../" + basename + "_ldd.txt ../../../" + basename + "_lines.txt ../../../" + basename + "_lines.dat && ./dat_convert.py ../../../" + basename + "_lines.dat)"; int status = system(cmd.c_str()); if ( status != 0 ) { std::cerr << "Error in creating the files used to generate " "the debug information. This might be caused because either " "`llvm-dwarfdump` or `Python` are not available. " "Please activate the CONDA environment and compile again.\n"; return status; } } #endif #else std::cerr << "Compiling Python files to object files requires the LLVM backend to be enabled. Recompile with `WITH_LLVM=yes`." << std::endl; return 1; #endif } else { throw LCompilers::LCompilersException("Unsupported backend."); } if (err != 0) return err; if (compiler_options.arg_o == "") { if (backend == Backend::wasm) { err = system(("node --experimental-wasi-unstable-preview1 " + outfile +".js").c_str()); } else { if (compiler_options.platform == LCompilers::Platform::Windows) { return system(outfile.c_str()); } else { err = system(("./" + outfile).c_str()); } } if (err != 0) { if (0 < err && err < 256) { return err; } else { return LCompilers::LPython::get_exit_status(err); } } } return 0; } else { return link_executable(arg_files, outfile, runtime_library_dir, backend, static_link, true, compiler_options, rtlib_header_dir); } } catch(const LCompilers::LCompilersException &e) { std::cerr << "Internal Compiler Error: Unhandled exception" << std::endl; std::vector<:stacktraceitem> d = e.stacktrace_addresses(); get_local_addresses(d); get_local_info(d); std::cerr << stacktrace2str(d, LCompilers::stacktrace_depth); std::cerr << e.name() + ": " << e.msg() << std::endl; return 1; } catch(const std::runtime_error &e) { std::cerr << "runtime_error: " << e.what() << std::endl; return 1; } catch(const std::exception &e) { std::cerr << "std::exception: " << e.what() << std::endl; return 1; } catch(...) { std::cerr << "Unknown Exception" << std::endl; return 1; } return 0; }