diff --git a/c.py b/c.py new file mode 100644 index 0000000000..11d8031a2c --- /dev/null +++ b/c.py @@ -0,0 +1,2 @@ +from b import j +print(j) diff --git a/examples/expr2.py b/examples/expr2.py index 2e66f1e584..c7db57f44a 100644 --- a/examples/expr2.py +++ b/examples/expr2.py @@ -1,6 +1,9 @@ +from a import i + def main0(): x: i32 - x = (2+3)*5 + x = i + x = 2.14 print(x) main0() diff --git a/expr2.py b/expr2.py new file mode 100644 index 0000000000..7169ec8e11 --- /dev/null +++ b/expr2.py @@ -0,0 +1,19 @@ +# from tmp import hi +from tmp2 import hi2 + +def main0(): + x: i32 + x = (2+3)*5 + print(x) + hi2() + # y: i32 = 3.1 + # # hi() + # p: i32 = 4.5 + # # hi2() + # print(y, p) + +main0() + +# Not implemented yet in LPython: +#if __name__ == "__main__": +# main() diff --git a/src/bin/lpython.cpp b/src/bin/lpython.cpp index 2701dfe85e..27d4b0276e 100644 --- a/src/bin/lpython.cpp +++ b/src/bin/lpython.cpp @@ -164,7 +164,7 @@ int emit_asr(const std::string &infile, diagnostics.diagnostics.clear(); LFortran::Result - r = LFortran::LPython::python_ast_to_asr(al, *ast, diagnostics, compiler_options, true, infile); + r = LFortran::LPython::python_ast_to_asr(al, *ast, lm, diagnostics, compiler_options, true, infile, input); std::cerr << diagnostics.render(input, lm, compiler_options); if (!r.ok) { LFORTRAN_ASSERT(diagnostics.has_error()) @@ -206,7 +206,7 @@ int emit_cpp(const std::string &infile, diagnostics.diagnostics.clear(); LFortran::Result - r1 = LFortran::LPython::python_ast_to_asr(al, *ast, diagnostics, compiler_options, true, infile); + r1 = LFortran::LPython::python_ast_to_asr(al, *ast, lm, diagnostics, compiler_options, true, infile, input); std::cerr << diagnostics.render(input, lm, compiler_options); if (!r1.ok) { LFORTRAN_ASSERT(diagnostics.has_error()) @@ -246,7 +246,7 @@ int emit_c(const std::string &infile, diagnostics.diagnostics.clear(); LFortran::Result - r1 = LFortran::LPython::python_ast_to_asr(al, *ast, diagnostics, compiler_options, true, infile); + r1 = LFortran::LPython::python_ast_to_asr(al, *ast, lm, diagnostics, compiler_options, true, infile, input); std::cerr << diagnostics.render(input, lm, compiler_options); if (!r1.ok) { LFORTRAN_ASSERT(diagnostics.has_error()) @@ -286,7 +286,7 @@ int emit_wat(const std::string &infile, diagnostics.diagnostics.clear(); LFortran::Result - r1 = LFortran::LPython::python_ast_to_asr(al, *ast, diagnostics, compiler_options, true, infile); + r1 = LFortran::LPython::python_ast_to_asr(al, *ast, lm, diagnostics, compiler_options, true, infile, input); std::cerr << diagnostics.render(input, lm, compiler_options); if (!r1.ok) { LFORTRAN_ASSERT(diagnostics.has_error()) @@ -329,7 +329,7 @@ int get_symbols (const std::string &infile, if (r1.ok) { LFortran::LPython::AST::ast_t* ast = r1.result; LFortran::Result - x = LFortran::LPython::python_ast_to_asr(al, *ast, diagnostics, compiler_options, true, infile); + x = LFortran::LPython::python_ast_to_asr(al, *ast, lm, diagnostics, compiler_options, true, infile, input); if (!x.ok) { std::cout << "{}\n"; return 0; @@ -421,7 +421,7 @@ int get_errors (const std::string &infile, if (r1.ok) { LFortran::LPython::AST::ast_t* ast = r1.result; LFortran::Result - r = LFortran::LPython::python_ast_to_asr(al, *ast, diagnostics, compiler_options, true, infile); + r = LFortran::LPython::python_ast_to_asr(al, *ast, lm, diagnostics, compiler_options, true, infile, input); } std::vector diag_lists; LFortran::LPython::error_highlight h; @@ -532,7 +532,7 @@ int emit_llvm(const std::string &infile, LFortran::LPython::AST::ast_t* ast = r.result; diagnostics.diagnostics.clear(); LFortran::Result - r1 = LFortran::LPython::python_ast_to_asr(al, *ast, diagnostics, compiler_options, true, infile); + r1 = LFortran::LPython::python_ast_to_asr(al, *ast, lm, diagnostics, compiler_options, true, infile, input); std::cerr << diagnostics.render(input, lm, compiler_options); if (!r1.ok) { LFORTRAN_ASSERT(diagnostics.has_error()) @@ -572,6 +572,7 @@ int compile_python_to_object_file( 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); + std::cout << "lpython.cpp: " << lm.files[0].in_filename << std::endl; auto parsing_start = std::chrono::high_resolution_clock::now(); LFortran::Result r = parse_python_file( al, runtime_library_dir, infile, diagnostics, compiler_options.new_parser); @@ -588,11 +589,12 @@ int compile_python_to_object_file( diagnostics.diagnostics.clear(); auto ast_to_asr_start = std::chrono::high_resolution_clock::now(); LFortran::Result - r1 = LFortran::LPython::python_ast_to_asr(al, *ast, diagnostics, compiler_options, - !(arg_c && compiler_options.disable_main), infile); + r1 = LFortran::LPython::python_ast_to_asr(al, *ast, lm, diagnostics, compiler_options, + !(arg_c && compiler_options.disable_main), infile, input); 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::cout << "input: \n" << input << std::endl; std::cerr << diagnostics.render(input, lm, compiler_options); if (!r1.ok) { LFORTRAN_ASSERT(diagnostics.has_error()) @@ -672,7 +674,7 @@ int compile_to_binary_wasm( diagnostics.diagnostics.clear(); auto ast_to_asr_start = std::chrono::high_resolution_clock::now(); LFortran::Result - r1 = LFortran::LPython::python_ast_to_asr(al, *ast, diagnostics, compiler_options, true, infile); + r1 = LFortran::LPython::python_ast_to_asr(al, *ast, lm, diagnostics, compiler_options, true, infile, input); 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(input, lm, compiler_options); @@ -737,7 +739,7 @@ int compile_to_binary_x86( diagnostics.diagnostics.clear(); auto ast_to_asr_start = std::chrono::high_resolution_clock::now(); LFortran::Result - r1 = LFortran::LPython::python_ast_to_asr(al, *ast, diagnostics, compiler_options, true, infile); + r1 = LFortran::LPython::python_ast_to_asr(al, *ast, lm, diagnostics, compiler_options, true, infile, input); 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(input, lm, compiler_options); @@ -802,7 +804,7 @@ int compile_to_binary_wasm_to_x86( diagnostics.diagnostics.clear(); auto ast_to_asr_start = std::chrono::high_resolution_clock::now(); LFortran::Result - r1 = LFortran::LPython::python_ast_to_asr(al, *ast, diagnostics, compiler_options, true, infile); + r1 = LFortran::LPython::python_ast_to_asr(al, *ast, lm, diagnostics, compiler_options, true, infile, input); 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(input, lm, compiler_options); @@ -1067,7 +1069,7 @@ EMSCRIPTEN_KEEPALIVE char* emit_asr_from_source(char *input) { if (ast.ok) { auto casted_ast = (LFortran::LPython::AST::ast_t*)ast.result; LFortran::Result - asr = LFortran::LPython::python_ast_to_asr(al, *casted_ast, diagnostics, compiler_options, true, "input"); + asr = LFortran::LPython::python_ast_to_asr(al, *casted_ast, diagnostics, compiler_options, true, "input", input); out = diagnostics.render(input, lm, compiler_options); if (asr.ok) { out += LFortran::pickle(*asr.result, compiler_options.use_colors, compiler_options.indent, @@ -1085,7 +1087,7 @@ EMSCRIPTEN_KEEPALIVE char* emit_wat_from_source(char *input) { if (ast.ok) { auto casted_ast = (LFortran::LPython::AST::ast_t*)ast.result; LFortran::Result - asr = LFortran::LPython::python_ast_to_asr(al, *casted_ast, diagnostics, compiler_options, true, "input"); + asr = LFortran::LPython::python_ast_to_asr(al, *casted_ast, diagnostics, compiler_options, true, "input", input); out = diagnostics.render(input, lm, compiler_options); if (asr.ok) { LFortran::Result> @@ -1112,7 +1114,7 @@ EMSCRIPTEN_KEEPALIVE char* emit_cpp_from_source(char *input) { if (ast.ok) { auto casted_ast = (LFortran::LPython::AST::ast_t*)ast.result; LFortran::Result - asr = LFortran::LPython::python_ast_to_asr(al, *casted_ast, diagnostics, compiler_options, true, "input"); + asr = LFortran::LPython::python_ast_to_asr(al, *casted_ast, diagnostics, compiler_options, true, "input", input); out = diagnostics.render(input, lm, compiler_options); if (asr.ok) { auto res = LFortran::asr_to_cpp(al, *asr.result, diagnostics, @@ -1150,7 +1152,7 @@ EMSCRIPTEN_KEEPALIVE char* emit_wasm_from_source(char *input) { if (ast.ok) { auto casted_ast = (LFortran::LPython::AST::ast_t*)ast.result; LFortran::Result - asr = LFortran::LPython::python_ast_to_asr(al, *casted_ast, diagnostics, compiler_options, true, "input"); + asr = LFortran::LPython::python_ast_to_asr(al, *casted_ast, diagnostics, compiler_options, true, "input", input); out = diagnostics.render(input, lm, compiler_options); if (asr.ok) { LFortran::Result> diff --git a/src/libasr/codegen/asr_to_llvm.cpp b/src/libasr/codegen/asr_to_llvm.cpp index fd0fcc3336..b599e658ea 100644 --- a/src/libasr/codegen/asr_to_llvm.cpp +++ b/src/libasr/codegen/asr_to_llvm.cpp @@ -381,9 +381,9 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor void debug_get_line_column(const uint32_t &loc_first, uint32_t &line, uint32_t &column) { LocationManager lm; - lm.in_filename = infile; - lm.init_simple(LFortran::read_file(infile)); - lm.pos_to_linecol(lm.output_to_input_pos(loc_first, false), line, column); + lm.lm.in_filename = infile; + lm.lm.init_simple(LFortran::read_file(infile)); + lm.lm.pos_to_linecol(lm.lm.output_to_input_pos(loc_first, false), line, column); } template diff --git a/src/libasr/diagnostics.cpp b/src/libasr/diagnostics.cpp index 2684466fee..f7c1d96e52 100644 --- a/src/libasr/diagnostics.cpp +++ b/src/libasr/diagnostics.cpp @@ -110,11 +110,11 @@ std::string get_line(std::string str, int n) void populate_span(diag::Span &s, const LocationManager &lm, const std::string &input) { - lm.pos_to_linecol(lm.output_to_input_pos(s.loc.first, false), - s.first_line, s.first_column); - lm.pos_to_linecol(lm.output_to_input_pos(s.loc.last, true), - s.last_line, s.last_column); - s.filename = lm.in_filename; + lm.pos_to_linecol(s.loc.first, + s.first_line, s.first_column, s.filename); + lm.pos_to_linecol(s.loc.last, + s.last_line, s.last_column, s.filename); + // s.filename = lm.in_filename; for (uint32_t i = s.first_line; i <= s.last_line; i++) { s.source_code.push_back(get_line(input, i)); } @@ -178,7 +178,7 @@ std::string render_diagnostic_human(const Diagnostic &d, bool use_colors) { std::string type_color = ""; switch (d.level) { case (Level::Error): - primary_color = red_bold; + primary_color = red_bold; type_color = primary_color; switch (d.stage) { case (Stage::CPreprocessor): @@ -205,17 +205,17 @@ std::string render_diagnostic_human(const Diagnostic &d, bool use_colors) { } break; case (Level::Warning): - primary_color = yellow_bold; + primary_color = yellow_bold; type_color = primary_color; message_type = "warning"; break; case (Level::Note): - primary_color = bold; + primary_color = bold; type_color = primary_color; message_type = "note"; break; case (Level::Help): - primary_color = bold; + primary_color = bold; type_color = primary_color; message_type = "help"; break; diff --git a/src/libasr/location.h b/src/libasr/location.h index a38d8175ce..342dd487fe 100644 --- a/src/libasr/location.h +++ b/src/libasr/location.h @@ -3,6 +3,7 @@ #include #include +#include namespace LFortran { @@ -94,94 +95,144 @@ struct LocationManager { // // // - std::vector out_start; // consecutive intervals in the output code - std::vector in_start; // start + size in the original code - std::vector in_newlines; // position of all \n in the original code - - // For preprocessor (if preprocessor==true). - // TODO: design a common structure, that also works with #include, that - // has these mappings for each file - bool preprocessor = false; - std::string in_filename; - uint32_t current_line=0; - std::vector out_start0; // consecutive intervals in the output code - std::vector in_start0; // start + size in the original code - std::vector in_size0; // Size of the `in` interval - std::vector interval_type0; // 0 .... 1:1; 1 ... many to many; - std::vector in_newlines0; // position of all \n in the original code -// std::vector filename_id; // file name for each interval, ID -// std::vector filenames; // filenames lookup for an ID - - // Converts a position in the output code to a position in the original code - // Every character in the output code has a corresponding location in the - // original code, so this function always succeeds - uint32_t output_to_input_pos(uint32_t out_pos, bool show_last) const { - if (out_start.size() == 0) return 0; - uint32_t interval = bisection(out_start, out_pos)-1; - uint32_t rel_pos = out_pos - out_start[interval]; - uint32_t in_pos = in_start[interval] + rel_pos; - if (preprocessor) { - // If preprocessor was used, do one more remapping - uint32_t interval0 = bisection(out_start0, in_pos)-1; - if (interval_type0[interval0] == 0) { - // 1:1 interval - uint32_t rel_pos0 = in_pos - out_start0[interval0]; - uint32_t in_pos0 = in_start0[interval0] + rel_pos0; - return in_pos0; - } else { - // many to many interval - uint32_t in_pos0; - if (in_pos == out_start0[interval0+1]-1 || show_last) { - // The end of the interval in "out" code - // Return the end of the interval in "in" code - in_pos0 = in_start0[interval0]+in_size0[interval0]-1; + struct FileLocations { + std::vector out_start; // consecutive intervals in the output code + std::vector in_start; // start + size in the original code + std::vector in_newlines; // position of all \n in the original code + + // For preprocessor (if preprocessor==true). + // TODO: design a common structure, that also works with #include, that + // has these mappings for each file + bool preprocessor = false; + std::string in_filename; + uint32_t current_line=0; + std::vector out_start0; // consecutive intervals in the output code + std::vector in_start0; // start + size in the original code + std::vector in_size0; // Size of the `in` interval + std::vector interval_type0; // 0 .... 1:1; 1 ... many to many; + std::vector in_newlines0; // position of all \n in the original code + + // Converts a position in the output code to a position in the original code + // Every character in the output code has a corresponding location in the + // original code, so this function always succeeds + uint32_t output_to_input_pos(uint32_t out_pos, bool show_last) const { + if (out_start.size() == 0) return 0; + uint32_t interval = bisection(out_start, out_pos)-1; + uint32_t rel_pos = out_pos - out_start[interval]; + uint32_t in_pos = in_start[interval] + rel_pos; + if (preprocessor) { + // If preprocessor was used, do one more remapping + uint32_t interval0 = bisection(out_start0, in_pos)-1; + if (interval_type0[interval0] == 0) { + // 1:1 interval + uint32_t rel_pos0 = in_pos - out_start0[interval0]; + uint32_t in_pos0 = in_start0[interval0] + rel_pos0; + return in_pos0; } else { - // Otherwise return the beginning of the interval in "in" - in_pos0 = in_start0[interval0]; + // many to many interval + uint32_t in_pos0; + if (in_pos == out_start0[interval0+1]-1 || show_last) { + // The end of the interval in "out" code + // Return the end of the interval in "in" code + in_pos0 = in_start0[interval0]+in_size0[interval0]-1; + } else { + // Otherwise return the beginning of the interval in "in" + in_pos0 = in_start0[interval0]; + } + return in_pos0; } - return in_pos0; + } else { + return in_pos; } - } else { - return in_pos; } - } - // Converts a linear position `position` to a (line, col) tuple - // `position` starts from 0 - // `line` and `col` starts from 1 - // `in_newlines` starts from 0 - void pos_to_linecol(uint32_t position, uint32_t &line, uint32_t &col) const { - const std::vector *newlines; - if (preprocessor) { - newlines = &in_newlines0; - } else { - newlines = &in_newlines; + // Converts a linear position `position` to a (line, col) tuple + // `position` starts from 0 + // `line` and `col` starts from 1 + // `in_newlines` starts from 0 + void pos_to_linecol(uint32_t position, uint32_t &line, uint32_t &col) const { + const std::vector *newlines; + if (preprocessor) { + newlines = &in_newlines0; + } else { + newlines = &in_newlines; + } + int32_t interval = bisection(*newlines, position); + if (interval >= 1 && position == (*newlines)[interval-1]) { + // position is exactly the \n character, make sure `line` is + // the line with \n, and `col` points to the position of \n + interval -= 1; + } + line = interval+1; + if (line == 1) { + col = position+1; + } else { + col = position-(*newlines)[interval-1]; + } } - int32_t interval = bisection(*newlines, position); - if (interval >= 1 && position == (*newlines)[interval-1]) { - // position is exactly the \n character, make sure `line` is - // the line with \n, and `col` points to the position of \n - interval -= 1; + + void get_newlines(const std::string &s, std::vector &newlines) { + for (uint32_t pos=0; pos < s.size(); pos++) { + if (s[pos] == '\n') newlines.push_back(pos); + } } - line = interval+1; - if (line == 1) { - col = position+1; - } else { - col = position-(*newlines)[interval-1]; + + void init_simple(const std::string &input) { + uint32_t n = input.size(); + out_start = {0, n}; + in_start = {0, n}; + get_newlines(input, in_newlines); } - } + }; + + std::string in_filename; + FileLocations lm; + std::vector files; + std::vector file_ends; // position of all ends of files + // For a given Location we use the `file_ends` and bisection to determine + // the file (index) which the location is from. Then we use this index into + // the `files` vector and use `in_newlines` and other information to + // determin the line and column inside this file, and the `in_filename` + // field to determine the filename. This happens when the diagnostic is + // printed. The `pos_to_linecol` function below should be modified to + // return line, column and the filename: + // + void pos_to_linecol(uint32_t position, uint32_t &line, uint32_t &col, + std::string &filename) const { - void get_newlines(const std::string &s, std::vector &newlines) { - for (uint32_t pos=0; pos < s.size(); pos++) { - if (s[pos] == '\n') newlines.push_back(pos); + std::cout << "I am here-1" << std::endl; + for (size_t i = 0; i < file_ends.size(); i++) { + std::cout << "I am here-2" << std::endl; + if (position < file_ends[i]) { + std::cout << "I am here-3" << std::endl; + files[i].pos_to_linecol(files[i].output_to_input_pos(position, false), line, col); + filename = files[i].in_filename; + std::cout << "Filename: " << filename << std::endl; + return; + } } + + // files.back().pos_to_linecol(files.back().output_to_input_pos(position, false), line, col); + // filename = files.back().in_filename; + // std::cout << "Filename: " << filename << std::endl; + // return; } void init_simple(const std::string &input) { uint32_t n = input.size(); - out_start = {0, n}; - in_start = {0, n}; - get_newlines(input, in_newlines); + FileLocations file_loc; + file_loc.in_filename = this->in_filename; + if (file_ends.empty()) { + file_loc.out_start = {0, n}; + file_loc.in_start = {0, n}; + file_ends.push_back(n); // is this fine?? + } else { + file_loc.out_start = {0, n}; + file_loc.in_start = {file_ends.back(), file_ends.back() + n}; // is this fine?? + file_ends.push_back(file_ends.back() + n); // is this fine?? + } + file_loc.get_newlines(input, file_loc.in_newlines); + files.push_back(file_loc); } }; diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index d1e115c9fe..53648f609a 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -240,12 +240,13 @@ bool set_module_path(std::string infile0, std::vector &rl_path, } ASR::TranslationUnit_t* compile_module_till_asr(Allocator& al, + LocationManager &lm, diag::Diagnostics &diagnostics, std::vector &rl_path, std::string infile, const Location &loc, const std::function err, + std::string &src_code, bool allow_implicit_casting) { // TODO: diagnostic should be an argument to this function - diag::Diagnostics diagnostics; Result r = parse_python_file(al, rl_path[0], infile, diagnostics, false); if (!r.ok) { @@ -254,20 +255,25 @@ ASR::TranslationUnit_t* compile_module_till_asr(Allocator& al, LFortran::LPython::AST::ast_t* ast = r.result; // Convert the module from AST to ASR - LFortran::LocationManager lm; lm.in_filename = infile; LFortran::CompilerOptions compiler_options; compiler_options.disable_main = true; compiler_options.symtab_only = false; - Result r2 = python_ast_to_asr(al, *ast, - diagnostics, compiler_options, false, infile, allow_implicit_casting); + Result r2 = python_ast_to_asr(al, *ast, lm, + diagnostics, compiler_options, false, infile, src_code, allow_implicit_casting); // TODO: Uncomment once a check is added for ensuring // that module.py file hasn't changed between // builds. // save_pyc_files(*r2.result, infile + "c"); std::string input; read_file(infile, input); - std::cerr << diagnostics.render(input, lm, compiler_options); + lm.init_simple(input); + src_code += input; + + + std::cout << "lm.file_ends.size()" << lm.file_ends.size() << std::endl; + // std::cout << "src_code" << src_code << std::endl; + // std::cerr << diagnostics.render(input, lm, compiler_options); if (!r2.ok) { LFORTRAN_ASSERT(diagnostics.has_error()) return nullptr; // Error @@ -291,12 +297,16 @@ void fill_module_dependencies(SymbolTable* symtab, std::set& mod_de } } -ASR::Module_t* load_module(Allocator &al, SymbolTable *symtab, +ASR::Module_t* load_module(Allocator &al, + LocationManager &lm, + diag::Diagnostics &diag, + SymbolTable *symtab, const std::string &module_name, const Location &loc, bool intrinsic, std::vector &rl_path, bool <ypes, bool& enum_py, const std::function err, + std::string &src_code, bool allow_implicit_casting) { if( module_name == "copy" ) { return nullptr; @@ -345,7 +355,11 @@ ASR::Module_t* load_module(Allocator &al, SymbolTable *symtab, if (ltypes) return nullptr; if( compile_module ) { - mod1 = compile_module_till_asr(al, rl_path, infile, loc, err, allow_implicit_casting); + mod1 = compile_module_till_asr(al, lm, diag, rl_path, infile, loc, err, src_code, allow_implicit_casting); + } + + if (!mod1) { + return nullptr; } // insert into `symtab` @@ -513,15 +527,17 @@ class CommonVisitor : public AST::BaseVisitor { std::map> generic_func_subs; std::vector rt_vec; std::set dependencies; + std::string &src_code; + LocationManager &lm; bool allow_implicit_casting; CommonVisitor(Allocator &al, SymbolTable *symbol_table, diag::Diagnostics &diagnostics, bool main_module, std::map &ast_overload, std::string parent_dir, - std::string import_path, bool allow_implicit_casting_) + std::string import_path, std::string &src_code, LocationManager &lm, bool allow_implicit_casting_) : diag{diagnostics}, al{al}, current_scope{symbol_table}, main_module{main_module}, ast_overload{ast_overload}, parent_dir{parent_dir}, import_path{import_path}, - current_body{nullptr}, ann_assign_target_type{nullptr}, + current_body{nullptr}, ann_assign_target_type{nullptr}, src_code{src_code}, lm{lm}, allow_implicit_casting{allow_implicit_casting_} { current_module_dependencies.reserve(al, 4); } @@ -546,11 +562,11 @@ class CommonVisitor : public AST::BaseVisitor { std::string rl_path = get_runtime_library_dir(); std::vector paths = {rl_path, parent_dir}; bool ltypes, enum_py; - ASR::Module_t *m = load_module(al, tu_symtab, module_name, + ASR::Module_t *m = load_module(al, lm, diag, tu_symtab, module_name, loc, true, paths, ltypes, enum_py, [&](const std::string &msg, const Location &loc) { throw SemanticError(msg, loc); }, - allow_implicit_casting); + src_code, allow_implicit_casting); LFORTRAN_ASSERT(!ltypes && !enum_py) ASR::symbol_t *t = m->m_symtab->resolve_symbol(remote_sym); @@ -3115,13 +3131,13 @@ class SymbolTableVisitor : public CommonVisitor { std::vector excluded_from_symtab; std::map> overload_defs; - SymbolTableVisitor(Allocator &al, SymbolTable *symbol_table, + LocationManager &lm, diag::Diagnostics &diagnostics, bool main_module, std::map &ast_overload, std::string parent_dir, - std::string import_path, bool allow_implicit_casting_) + std::string import_path, std::string &src_code, bool allow_implicit_casting_) : CommonVisitor(al, symbol_table, diagnostics, main_module, ast_overload, - parent_dir, import_path, allow_implicit_casting_), is_derived_type{false} {} + parent_dir, import_path, src_code, lm, allow_implicit_casting_), is_derived_type{false} {} ASR::symbol_t* resolve_symbol(const Location &loc, const std::string &sub_name) { @@ -3441,10 +3457,10 @@ class SymbolTableVisitor : public CommonVisitor { msym = "__init__"; } } - t = (ASR::symbol_t*)(load_module(al, st, + t = (ASR::symbol_t*)(load_module(al, lm, diag, st, msym, x.base.base.loc, false, paths, ltypes, enum_py, [&](const std::string &msg, const Location &loc) { throw SemanticError(msg, loc); }, - allow_implicit_casting)); + src_code, allow_implicit_casting)); if (ltypes || enum_py) { // TODO: For now we skip ltypes import completely. Later on we should note what symbols // got imported from it, and give an error message if an annotation is used without @@ -3453,8 +3469,14 @@ class SymbolTableVisitor : public CommonVisitor { return; } if (!t) { - throw SemanticError("The module '" + msym + "' cannot be loaded", + diag.message_label("Imported here", {x.base.base.loc}, "", + diag::Level::Note, diag::Stage::Semantic); + if (main_module) { + throw SemanticError("The module '" + msym + "' cannot be loaded", x.base.base.loc); + } else { + throw SemanticAbort(); + } } current_module_dependencies.push_back(al, s2c(al, msym)); } @@ -3512,10 +3534,10 @@ class SymbolTableVisitor : public CommonVisitor { mod_sym = "__init__"; } } - t = (ASR::symbol_t*)(load_module(al, st, + t = (ASR::symbol_t*)(load_module(al, lm, diag, st, mod_sym, x.base.base.loc, false, paths, ltypes, enum_py, [&](const std::string &msg, const Location &loc) { throw SemanticError(msg, loc); }, - allow_implicit_casting)); + src_code, allow_implicit_casting)); if (ltypes || enum_py) { // TODO: For now we skip ltypes import completely. Later on we should note what symbols // got imported from it, and give an error message if an annotation is used without @@ -3615,12 +3637,12 @@ class SymbolTableVisitor : public CommonVisitor { }; Result symbol_table_visitor(Allocator &al, const AST::Module_t &ast, - diag::Diagnostics &diagnostics, bool main_module, + LFortran::LocationManager &lm, diag::Diagnostics &diagnostics, bool main_module, std::map &ast_overload, std::string parent_dir, - std::string import_path, bool allow_implicit_casting) + std::string import_path, std::string &src_code, bool allow_implicit_casting) { - SymbolTableVisitor v(al, nullptr, diagnostics, main_module, ast_overload, - parent_dir, import_path, allow_implicit_casting); + SymbolTableVisitor v(al, nullptr, lm, diagnostics, main_module, ast_overload, + parent_dir, import_path, src_code, allow_implicit_casting); try { v.visit_Module(ast); } catch (const SemanticError &e) { @@ -3644,10 +3666,10 @@ class BodyVisitor : public CommonVisitor { int64_t gotoids; - BodyVisitor(Allocator &al, ASR::asr_t *unit, diag::Diagnostics &diagnostics, - bool main_module, std::map &ast_overload, + BodyVisitor(Allocator &al, ASR::asr_t *unit, LocationManager &lm, diag::Diagnostics &diagnostics, + bool main_module, std::map &ast_overload, std::string &src_code, bool allow_implicit_casting_) - : CommonVisitor(al, nullptr, diagnostics, main_module, ast_overload, "", "", allow_implicit_casting_), + : CommonVisitor(al, nullptr, diagnostics, main_module, ast_overload, "", "", src_code, lm, allow_implicit_casting_), asr{unit}, gotoids{0} {} @@ -5752,12 +5774,14 @@ class BodyVisitor : public CommonVisitor { Result body_visitor(Allocator &al, const AST::Module_t &ast, + LocationManager &lm, diag::Diagnostics &diagnostics, ASR::asr_t *unit, bool main_module, std::map &ast_overload, + std::string &src_code, bool allow_implicit_casting) { - BodyVisitor b(al, unit, diagnostics, main_module, ast_overload, allow_implicit_casting); + BodyVisitor b(al, unit, lm, diagnostics, main_module, ast_overload, src_code, allow_implicit_casting); try { b.visit_Module(ast); } catch (const SemanticError &e) { @@ -5813,16 +5837,16 @@ std::string get_parent_dir(const std::string &path) { } Result python_ast_to_asr(Allocator &al, - AST::ast_t &ast, diag::Diagnostics &diagnostics, CompilerOptions &compiler_options, - bool main_module, std::string file_path, bool allow_implicit_casting) + AST::ast_t &ast, LFortran::LocationManager &lm, diag::Diagnostics &diagnostics, CompilerOptions &compiler_options, + bool main_module, std::string file_path, std::string &src_code, bool allow_implicit_casting) { std::map ast_overload; std::string parent_dir = get_parent_dir(file_path); AST::Module_t *ast_m = AST::down_cast2(&ast); ASR::asr_t *unit; - auto res = symbol_table_visitor(al, *ast_m, diagnostics, main_module, - ast_overload, parent_dir, compiler_options.import_path, allow_implicit_casting); + auto res = symbol_table_visitor(al, *ast_m, lm, diagnostics, main_module, + ast_overload, parent_dir, compiler_options.import_path, src_code, allow_implicit_casting); if (res.ok) { unit = res.result; } else { @@ -5832,8 +5856,8 @@ Result python_ast_to_asr(Allocator &al, LFORTRAN_ASSERT(asr_verify(*tu)); if (!compiler_options.symtab_only) { - auto res2 = body_visitor(al, *ast_m, diagnostics, unit, main_module, - ast_overload, allow_implicit_casting); + auto res2 = body_visitor(al, *ast_m, lm, diagnostics, unit, main_module, + ast_overload, src_code, allow_implicit_casting); if (res2.ok) { tu = res2.result; } else { diff --git a/src/lpython/semantics/python_ast_to_asr.h b/src/lpython/semantics/python_ast_to_asr.h index 72f18ac1db..ca6e118f53 100644 --- a/src/lpython/semantics/python_ast_to_asr.h +++ b/src/lpython/semantics/python_ast_to_asr.h @@ -9,8 +9,8 @@ namespace LFortran::LPython { std::string pickle_python(AST::ast_t &ast, bool colors=false, bool indent=false); std::string pickle_tree_python(AST::ast_t &ast, bool colors=true); Result python_ast_to_asr(Allocator &al, - LPython::AST::ast_t &ast, diag::Diagnostics &diagnostics, CompilerOptions &compiler_options, - bool main_module, std::string file_path, bool allow_implicit_casting=false); + LPython::AST::ast_t &ast, LFortran::LocationManager &lm, diag::Diagnostics &diagnostics, CompilerOptions &compiler_options, + bool main_module, std::string file_path, std::string &input, bool allow_implicit_casting=false); int save_pyc_files(const LFortran::ASR::TranslationUnit_t &u, std::string infile); diff --git a/src/lpython/tests/test_error_rendering.cpp b/src/lpython/tests/test_error_rendering.cpp index 4fd2af3b95..6da213096d 100644 --- a/src/lpython/tests/test_error_rendering.cpp +++ b/src/lpython/tests/test_error_rendering.cpp @@ -62,12 +62,12 @@ TEST_CASE("Error Render: primary/secondary labels, single line") { Location loc1, loc2, loc3; LocationManager lm; input = "One line text\n"; - lm.in_filename = "input"; - lm.get_newlines(input, lm.in_newlines); - lm.out_start.push_back(0); - lm.in_start.push_back(0); - lm.in_start.push_back(input.size()); - lm.out_start.push_back(input.size()); + lm.lm.in_filename = "input"; + lm.lm.get_newlines(input, lm.lm.in_newlines); + lm.lm.out_start.push_back(0); + lm.lm.in_start.push_back(0); + lm.lm.in_start.push_back(input.size()); + lm.lm.out_start.push_back(input.size()); loc1.first = 4; loc1.last = 7; @@ -89,7 +89,7 @@ semantic error: Error with label no message --> input:1:5 | 1 | One line text - | ^^^^ + | ^^^^ )"""); CHECK(out == ref); @@ -233,12 +233,12 @@ TEST_CASE("Error Render: primary/secondary labels, multi line") { Location loc1, loc2, loc3; LocationManager lm; input = "One line text\nSecond line text\nThird line text\n"; - lm.in_filename = "input"; - lm.get_newlines(input, lm.in_newlines); - lm.out_start.push_back(0); - lm.in_start.push_back(0); - lm.in_start.push_back(input.size()); - lm.out_start.push_back(input.size()); + lm.lm.in_filename = "input"; + lm.lm.get_newlines(input, lm.lm.in_newlines); + lm.lm.out_start.push_back(0); + lm.lm.in_start.push_back(0); + lm.lm.in_start.push_back(input.size()); + lm.lm.out_start.push_back(input.size()); loc1.first = 4; // 1 line loc1.last = 24; // 2 line diff --git a/src/runtime/a.py b/src/runtime/a.py new file mode 100644 index 0000000000..fc8afb948e --- /dev/null +++ b/src/runtime/a.py @@ -0,0 +1 @@ +i: i32 = 3.14 diff --git a/src/runtime/b.py b/src/runtime/b.py new file mode 100644 index 0000000000..f0ecfdc635 --- /dev/null +++ b/src/runtime/b.py @@ -0,0 +1,2 @@ +from a import i +j: i32 = i diff --git a/src/runtime/tmp.py b/src/runtime/tmp.py new file mode 100644 index 0000000000..4301b27539 --- /dev/null +++ b/src/runtime/tmp.py @@ -0,0 +1,3 @@ +def hi(): + print("hi()") + i: i32 = 2.1 diff --git a/src/runtime/tmp2.py b/src/runtime/tmp2.py new file mode 100644 index 0000000000..0ae9391424 --- /dev/null +++ b/src/runtime/tmp2.py @@ -0,0 +1,5 @@ +from tmp import hi + +def hi2(): + print("hi2()") + hi()