#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>> ×, 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;
}