Skip to content

Commit 7a0c5ef

Browse files
XX Create new structure FileLocations to handle imported file errors
1 parent ce4612d commit 7a0c5ef

18 files changed

+449
-280
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ share/jupyter/kernels/fortran/kernel.json
6262
src/runtime/*.o.empty.c
6363
python_ast.py
6464
python_ast.h
65-
ser.txt
65+
input.txt
6666
integration_tests/py_*
6767
integration_tests/b1/*
6868
integration_tests/b2/*

examples/expr2.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
def main0():
22
x: i32
3-
x = (2+3)*5
4-
print(x)
3+
x = 1
54

65
main0()
76

src/bin/lpython.cpp

Lines changed: 209 additions & 131 deletions
Large diffs are not rendered by default.

src/libasr/codegen/asr_to_llvm.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -380,9 +380,15 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
380380
void debug_get_line_column(const uint32_t &loc_first,
381381
uint32_t &line, uint32_t &column) {
382382
LocationManager lm;
383-
lm.in_filename = infile;
384-
lm.init_simple(LFortran::read_file(infile));
385-
lm.pos_to_linecol(lm.output_to_input_pos(loc_first, false), line, column);
383+
LocationManager::FileLocations fl;
384+
fl.in_filename = infile;
385+
lm.files.push_back(fl);
386+
std::string input = LFortran::read_file(infile);
387+
// std::cout << infile << "\n" << input << "\n";
388+
lm.init_simple(input);
389+
lm.file_ends.push_back(input.size());
390+
lm.pos_to_linecol(lm.output_to_input_pos(loc_first, false),
391+
line, column, fl.in_filename);
386392
}
387393

388394
template <typename T>

src/libasr/diagnostics.cpp

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -61,20 +61,19 @@ bool Diagnostics::has_error() const {
6161
return false;
6262
}
6363

64-
std::string Diagnostics::render(const std::string &input,
65-
const LocationManager &lm, const CompilerOptions &compiler_options) {
64+
std::string Diagnostics::render(LocationManager &lm,
65+
const CompilerOptions &compiler_options) {
6666
std::string out;
6767
for (auto &d : this->diagnostics) {
6868
if (compiler_options.no_warnings && d.level != Level::Error) {
6969
continue;
7070
}
7171
if (compiler_options.error_format == "human") {
72-
out += render_diagnostic_human(d, input, lm,
73-
compiler_options.use_colors,
72+
out += render_diagnostic_human(d, lm, compiler_options.use_colors,
7473
compiler_options.show_stacktrace);
7574
if (&d != &this->diagnostics.back()) out += "\n";
7675
} else if (compiler_options.error_format == "short") {
77-
out += render_diagnostic_short(d, input, lm);
76+
out += render_diagnostic_short(d, lm);
7877
} else {
7978
throw LCompilersException("Error format not supported.");
8079
}
@@ -108,49 +107,48 @@ std::string get_line(std::string str, int n)
108107
return line;
109108
}
110109

111-
void populate_span(diag::Span &s, const LocationManager &lm,
112-
const std::string &input) {
110+
void populate_span(diag::Span &s, const LocationManager &lm) {
113111
lm.pos_to_linecol(lm.output_to_input_pos(s.loc.first, false),
114-
s.first_line, s.first_column);
112+
s.first_line, s.first_column, s.filename);
115113
lm.pos_to_linecol(lm.output_to_input_pos(s.loc.last, true),
116-
s.last_line, s.last_column);
117-
s.filename = lm.in_filename;
114+
s.last_line, s.last_column, s.filename);
115+
std::string input;
116+
read_file(s.filename, input);
117+
// std::cout << s.filename << "\n";
118118
for (uint32_t i = s.first_line; i <= s.last_line; i++) {
119119
s.source_code.push_back(get_line(input, i));
120120
}
121121
LFORTRAN_ASSERT(s.source_code.size() > 0)
122122
}
123123

124124
// Loop over all labels and their spans, populate all of them
125-
void populate_spans(diag::Diagnostic &d, const LocationManager &lm,
126-
const std::string &input) {
125+
void populate_spans(diag::Diagnostic &d, const LocationManager &lm) {
127126
for (auto &l : d.labels) {
128127
for (auto &s : l.spans) {
129-
populate_span(s, lm, input);
128+
populate_span(s, lm);
130129
}
131130
}
132131
}
133132

134133
// Fills Diagnostic with span details and renders it
135-
std::string render_diagnostic_human(Diagnostic &d, const std::string &input,
136-
const LocationManager &lm, bool use_colors, bool show_stacktrace) {
134+
std::string render_diagnostic_human(Diagnostic &d, const LocationManager &lm,
135+
bool use_colors, bool show_stacktrace) {
137136
std::string out;
138137
if (show_stacktrace) {
139138
out += error_stacktrace(d.stacktrace);
140139
}
141140
// Convert to line numbers and get source code strings
142-
populate_spans(d, lm, input);
141+
populate_spans(d, lm);
143142
// Render the message
144143
out += render_diagnostic_human(d, use_colors);
145144
return out;
146145
}
147146

148147
// Fills Diagnostic with span details and renders it
149-
std::string render_diagnostic_short(Diagnostic &d, const std::string &input,
150-
const LocationManager &lm) {
148+
std::string render_diagnostic_short(Diagnostic &d, const LocationManager &lm) {
151149
std::string out;
152150
// Convert to line numbers and get source code strings
153-
populate_spans(d, lm, input);
151+
populate_spans(d, lm);
154152
// Render the message
155153
out += render_diagnostic_short(d);
156154
return out;
@@ -178,7 +176,7 @@ std::string render_diagnostic_human(const Diagnostic &d, bool use_colors) {
178176
std::string type_color = "";
179177
switch (d.level) {
180178
case (Level::Error):
181-
primary_color = red_bold;
179+
primary_color = red_bold;
182180
type_color = primary_color;
183181
switch (d.stage) {
184182
case (Stage::CPreprocessor):
@@ -205,17 +203,17 @@ std::string render_diagnostic_human(const Diagnostic &d, bool use_colors) {
205203
}
206204
break;
207205
case (Level::Warning):
208-
primary_color = yellow_bold;
206+
primary_color = yellow_bold;
209207
type_color = primary_color;
210208
message_type = "warning";
211209
break;
212210
case (Level::Note):
213-
primary_color = bold;
211+
primary_color = bold;
214212
type_color = primary_color;
215213
message_type = "note";
216214
break;
217215
case (Level::Help):
218-
primary_color = bold;
216+
primary_color = bold;
219217
type_color = primary_color;
220218
message_type = "help";
221219
break;
@@ -286,6 +284,18 @@ std::string render_diagnostic_human(const Diagnostic &d, bool use_colors) {
286284
}
287285
// and start a new one:
288286
s0 = s2;
287+
if (s0.filename != s.filename) {
288+
out << std::endl;
289+
// TODO: print the primary line+column here, not the first label:
290+
out << std::string(line_num_width, ' ') << blue_bold;
291+
out << "-->" << reset << " " << s0.filename << ":";
292+
out << s0.first_line << ":" << s0.first_column;
293+
if (s0.first_line != s0.last_line) {
294+
out << " - " << s0.last_line << ":" << s0.last_column;
295+
}
296+
out << std::endl;
297+
}
298+
289299
if (s0.first_line == s0.last_line) {
290300
out << std::string(line_num_width+1, ' ') << blue_bold << "|"
291301
<< reset << std::endl;

src/libasr/diagnostics.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,7 @@ struct Diagnostic {
113113
struct Diagnostics {
114114
std::vector<Diagnostic> diagnostics;
115115

116-
std::string render(const std::string &input,
117-
const LocationManager &lm, const CompilerOptions &compiler_options);
116+
std::string render(LocationManager &lm, const CompilerOptions &compiler_options);
118117

119118
// Returns true iff diagnostics contains at least one error message
120119
bool has_error() const;
@@ -187,10 +186,9 @@ std::string render_diagnostic_human(const Diagnostic &d, bool use_colors);
187186
std::string render_diagnostic_short(const Diagnostic &d);
188187

189188
// Fills Diagnostic with span details and renders it
190-
std::string render_diagnostic_human(Diagnostic &d, const std::string &input,
191-
const LocationManager &lm, bool use_colors, bool show_stacktrace);
192-
std::string render_diagnostic_short(Diagnostic &d, const std::string &input,
193-
const LocationManager &lm);
189+
std::string render_diagnostic_human(Diagnostic &d, const LocationManager &lm,
190+
bool use_colors, bool show_stacktrace);
191+
std::string render_diagnostic_short(Diagnostic &d, const LocationManager &lm);
194192

195193
} // namespace diag
196194
} // namespace LFortran

src/libasr/location.h

Lines changed: 67 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <cstdint>
55
#include <vector>
6+
// #include <iostream>
67

78
namespace LFortran
89
{
@@ -94,50 +95,67 @@ struct LocationManager {
9495
//
9596
//
9697
//
97-
std::vector<uint32_t> out_start; // consecutive intervals in the output code
98-
std::vector<uint32_t> in_start; // start + size in the original code
99-
std::vector<uint32_t> in_newlines; // position of all \n in the original code
98+
struct FileLocations {
99+
std::vector<uint32_t> out_start; // consecutive intervals in the output code
100+
std::vector<uint32_t> in_start; // start + size in the original code
101+
std::vector<uint32_t> in_newlines; // position of all \n in the original code
100102

101-
// For preprocessor (if preprocessor==true).
102-
// TODO: design a common structure, that also works with #include, that
103-
// has these mappings for each file
104-
bool preprocessor = false;
105-
std::string in_filename;
106-
uint32_t current_line=0;
107-
std::vector<uint32_t> out_start0; // consecutive intervals in the output code
108-
std::vector<uint32_t> in_start0; // start + size in the original code
109-
std::vector<uint32_t> in_size0; // Size of the `in` interval
110-
std::vector<uint32_t> interval_type0; // 0 .... 1:1; 1 ... many to many;
111-
std::vector<uint32_t> in_newlines0; // position of all \n in the original code
112-
// std::vector<uint32_t> filename_id; // file name for each interval, ID
113-
// std::vector<std::string> filenames; // filenames lookup for an ID
103+
// For preprocessor (if preprocessor==true).
104+
// TODO: design a common structure, that also works with #include, that
105+
// has these mappings for each file
106+
bool preprocessor = false;
107+
std::string in_filename;
108+
uint32_t current_line=0;
109+
std::vector<uint32_t> out_start0; // consecutive intervals in the output code
110+
std::vector<uint32_t> in_start0; // start + size in the original code
111+
std::vector<uint32_t> in_size0; // Size of the `in` interval
112+
std::vector<uint32_t> interval_type0; // 0 .... 1:1; 1 ... many to many;
113+
std::vector<uint32_t> in_newlines0; // position of all \n in the original code
114+
};
115+
std::vector<FileLocations> files;
116+
std::vector<uint32_t> file_ends; // position of all ends of files
117+
// For a given Location we use the `file_ends` and bisection to determine
118+
// the file (index) which the location is from. Then we use this index into
119+
// the `files` vector and use `in_newlines` and other information to
120+
// determine the line and column inside this file, and the `in_filename`
121+
// field to determine the filename. This happens when the diagnostic is
122+
// printed. The `pos_to_linecol` function below should be modified to
123+
// return line, column and the filename:
124+
//
125+
// void pos_to_linecol(uint32_t position, uint32_t &line, uint32_t &col,
126+
// std::string &filename) const;
114127

115128
// Converts a position in the output code to a position in the original code
116129
// Every character in the output code has a corresponding location in the
117130
// original code, so this function always succeeds
118131
uint32_t output_to_input_pos(uint32_t out_pos, bool show_last) const {
119-
if (out_start.size() == 0) return 0;
120-
uint32_t interval = bisection(out_start, out_pos)-1;
121-
uint32_t rel_pos = out_pos - out_start[interval];
122-
uint32_t in_pos = in_start[interval] + rel_pos;
123-
if (preprocessor) {
132+
// std::cout << "out: " << out_pos << "\n";
133+
uint32_t index = bisection(file_ends, out_pos);
134+
if (index == file_ends.size()) index -= 1;
135+
// std::cout << index << ":\n";
136+
if (files[index].out_start.size() == 0) return 0;
137+
uint32_t interval = bisection(files[index].out_start, out_pos)-1;
138+
uint32_t rel_pos = out_pos - files[index].out_start[interval];
139+
uint32_t in_pos = files[index].in_start[interval] + rel_pos;
140+
// std::cout << "in: "<< in_pos << "\n";
141+
if (files[index].preprocessor) {
124142
// If preprocessor was used, do one more remapping
125-
uint32_t interval0 = bisection(out_start0, in_pos)-1;
126-
if (interval_type0[interval0] == 0) {
143+
uint32_t interval0 = bisection(files[index].out_start0, in_pos)-1;
144+
if (files[index].interval_type0[interval0] == 0) {
127145
// 1:1 interval
128-
uint32_t rel_pos0 = in_pos - out_start0[interval0];
129-
uint32_t in_pos0 = in_start0[interval0] + rel_pos0;
146+
uint32_t rel_pos0 = in_pos - files[index].out_start0[interval0];
147+
uint32_t in_pos0 = files[index].in_start0[interval0] + rel_pos0;
130148
return in_pos0;
131149
} else {
132150
// many to many interval
133151
uint32_t in_pos0;
134-
if (in_pos == out_start0[interval0+1]-1 || show_last) {
152+
if (in_pos == files[index].out_start0[interval0+1]-1 || show_last) {
135153
// The end of the interval in "out" code
136154
// Return the end of the interval in "in" code
137-
in_pos0 = in_start0[interval0]+in_size0[interval0]-1;
155+
in_pos0 = files[index].in_start0[interval0]+files[index].in_size0[interval0]-1;
138156
} else {
139157
// Otherwise return the beginning of the interval in "in"
140-
in_pos0 = in_start0[interval0];
158+
in_pos0 = files[index].in_start0[interval0];
141159
}
142160
return in_pos0;
143161
}
@@ -150,12 +168,26 @@ struct LocationManager {
150168
// `position` starts from 0
151169
// `line` and `col` starts from 1
152170
// `in_newlines` starts from 0
153-
void pos_to_linecol(uint32_t position, uint32_t &line, uint32_t &col) const {
171+
void pos_to_linecol(uint32_t position, uint32_t &line, uint32_t &col,
172+
std::string &filename) const {
173+
uint32_t index = bisection(file_ends, position);
174+
if (index == file_ends.size()) index -= 1;
175+
// std::cout << position << ": Pos1\n";
176+
filename = files[index].in_filename;
177+
// std::cout << "----------------------------\n";
178+
// for (auto &x: file_ends) std::cout << x << "\n";
179+
// std::cout << "----------------------------\n";
180+
// std::cout << file_ends[index] << ": "<< file_ends[index - 1] << ": " << position - file_ends[index - 1] << "\n";
181+
if (index > 0) position -= file_ends[index - 1];
182+
// std::cout << index << "_\n";
183+
// std::cout << position << ": Pos2\n";
184+
// std::cout << filename << ": Name\n";
185+
// exit(0);
154186
const std::vector<uint32_t> *newlines;
155-
if (preprocessor) {
156-
newlines = &in_newlines0;
187+
if (files[index].preprocessor) {
188+
newlines = &files[index].in_newlines0;
157189
} else {
158-
newlines = &in_newlines;
190+
newlines = &files[index].in_newlines;
159191
}
160192
int32_t interval = bisection(*newlines, position);
161193
if (interval >= 1 && position == (*newlines)[interval-1]) {
@@ -179,9 +211,9 @@ struct LocationManager {
179211

180212
void init_simple(const std::string &input) {
181213
uint32_t n = input.size();
182-
out_start = {0, n};
183-
in_start = {0, n};
184-
get_newlines(input, in_newlines);
214+
files.back().out_start = {0, n};
215+
files.back().in_start = {0, n};
216+
get_newlines(input, files.back().in_newlines);
185217
}
186218

187219
};

src/lpython/parser/parser.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515
namespace LFortran {
1616

1717
Result<LPython::AST::Module_t*> parse(Allocator &al, const std::string &s,
18-
diag::Diagnostics &diagnostics)
18+
uint32_t prev_loc, diag::Diagnostics &diagnostics)
1919
{
2020
Parser p(al, diagnostics);
2121
try {
22-
p.parse(s);
22+
p.parse(s, prev_loc);
2323
} catch (const parser_local::TokenizerError &e) {
2424
Error error;
2525
diagnostics.diagnostics.push_back(e.d);
@@ -42,15 +42,15 @@ Result<LPython::AST::Module_t*> parse(Allocator &al, const std::string &s,
4242
p.result.p, p.result.size(), p.type_ignore.p, p.type_ignore.size());
4343
}
4444

45-
void Parser::parse(const std::string &input)
45+
void Parser::parse(const std::string &input, uint32_t prev_loc)
4646
{
4747
inp = input;
4848
if (inp.size() > 0) {
4949
if (inp[inp.size()-1] != '\n') inp.append("\n");
5050
} else {
5151
inp.append("\n");
5252
}
53-
m_tokenizer.set_string(inp);
53+
m_tokenizer.set_string(inp, prev_loc);
5454
if (yyparse(*this) == 0) {
5555
return;
5656
}
@@ -116,13 +116,14 @@ Result<LPython::AST::ast_t*> parse_python_file(Allocator &al,
116116
const std::string &/*runtime_library_dir*/,
117117
const std::string &infile,
118118
diag::Diagnostics &diagnostics,
119+
uint32_t prev_loc,
119120
bool new_parser) {
120121
LPython::AST::ast_t* ast;
121122
// We will be using the new parser from now on
122123
new_parser = true;
123124
LFORTRAN_ASSERT(new_parser)
124125
std::string input = read_file(infile);
125-
Result<LPython::AST::Module_t*> res = parse(al, input, diagnostics);
126+
Result<LPython::AST::Module_t*> res = parse(al, input, prev_loc, diagnostics);
126127
if (res.ok) {
127128
ast = (LPython::AST::ast_t*)res.result;
128129
} else {

0 commit comments

Comments
 (0)