Skip to content

Commit 4ff2228

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

16 files changed

+263
-171
lines changed

src/bin/lpython.cpp

Lines changed: 73 additions & 65 deletions
Large diffs are not rendered by default.

src/libasr/codegen/asr_to_llvm.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,9 +380,11 @@ 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;
383+
LocationManager::FileLocations fl;
384+
fl.in_filename = infile;
385+
lm.files.push_back(fl);
384386
lm.init_simple(LFortran::read_file(infile));
385-
lm.pos_to_linecol(lm.output_to_input_pos(loc_first, false), line, column);
387+
lm.pos_to_linecol(lm.output_to_input_pos(loc_first, false), line, column, fl.in_filename);
386388
}
387389

388390
template <typename T>

src/libasr/diagnostics.cpp

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ bool Diagnostics::has_error() const {
6262
}
6363

6464
std::string Diagnostics::render(const std::string &input,
65-
const LocationManager &lm, const CompilerOptions &compiler_options) {
65+
LocationManager &lm, const CompilerOptions &compiler_options) {
6666
std::string out;
6767
for (auto &d : this->diagnostics) {
6868
if (compiler_options.no_warnings && d.level != Level::Error) {
@@ -109,12 +109,14 @@ std::string get_line(std::string str, int n)
109109
}
110110

111111
void populate_span(diag::Span &s, const LocationManager &lm,
112-
const std::string &input) {
112+
const std::string &/*input*/) {
113113
lm.pos_to_linecol(lm.output_to_input_pos(s.loc.first, false),
114-
s.first_line, s.first_column);
114+
s.first_line, s.first_column, s.filename);
115115
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;
116+
s.last_line, s.last_column, s.filename);
117+
std::string input;
118+
// std::cout << s.filename << "\n";
119+
read_file(s.filename, input);
118120
for (uint32_t i = s.first_line; i <= s.last_line; i++) {
119121
s.source_code.push_back(get_line(input, i));
120122
}
@@ -178,7 +180,7 @@ std::string render_diagnostic_human(const Diagnostic &d, bool use_colors) {
178180
std::string type_color = "";
179181
switch (d.level) {
180182
case (Level::Error):
181-
primary_color = red_bold;
183+
primary_color = red_bold;
182184
type_color = primary_color;
183185
switch (d.stage) {
184186
case (Stage::CPreprocessor):
@@ -205,17 +207,17 @@ std::string render_diagnostic_human(const Diagnostic &d, bool use_colors) {
205207
}
206208
break;
207209
case (Level::Warning):
208-
primary_color = yellow_bold;
210+
primary_color = yellow_bold;
209211
type_color = primary_color;
210212
message_type = "warning";
211213
break;
212214
case (Level::Note):
213-
primary_color = bold;
215+
primary_color = bold;
214216
type_color = primary_color;
215217
message_type = "note";
216218
break;
217219
case (Level::Help):
218-
primary_color = bold;
220+
primary_color = bold;
219221
type_color = primary_color;
220222
message_type = "help";
221223
break;
@@ -286,6 +288,18 @@ std::string render_diagnostic_human(const Diagnostic &d, bool use_colors) {
286288
}
287289
// and start a new one:
288290
s0 = s2;
291+
if (s0.filename != s.filename) {
292+
out << std::endl;
293+
// TODO: print the primary line+column here, not the first label:
294+
out << std::string(line_num_width, ' ') << blue_bold;
295+
out << "-->" << reset << " " << s0.filename << ":";
296+
out << s0.first_line << ":" << s0.first_column;
297+
if (s0.first_line != s0.last_line) {
298+
out << " - " << s0.last_line << ":" << s0.last_column;
299+
}
300+
out << std::endl;
301+
}
302+
289303
if (s0.first_line == s0.last_line) {
290304
out << std::string(line_num_width+1, ' ') << blue_bold << "|"
291305
<< reset << std::endl;

src/libasr/diagnostics.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ struct Diagnostics {
114114
std::vector<Diagnostic> diagnostics;
115115

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

119119
// Returns true iff diagnostics contains at least one error message
120120
bool has_error() const;

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 {

src/lpython/parser/parser.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,21 @@ class Parser
2626
type_ignore.reserve(al, 4);
2727
}
2828

29-
void parse(const std::string &input);
29+
void parse(const std::string &input, uint32_t prev_loc);
3030
void handle_yyerror(const Location &loc, const std::string &msg);
3131
};
3232

3333

3434
// Parses Python code to AST
3535
Result<LPython::AST::Module_t*> parse(Allocator &al,
36-
const std::string &s,
36+
const std::string &s, uint32_t prev_loc,
3737
diag::Diagnostics &diagnostics);
3838

3939
Result<LPython::AST::ast_t*> parse_python_file(Allocator &al,
4040
const std::string &runtime_library_dir,
4141
const std::string &infile,
4242
diag::Diagnostics &diagnostics,
43-
bool new_parser);
43+
uint32_t prev_loc, bool new_parser);
4444

4545
} // namespace LFortran
4646

src/lpython/parser/tokenizer.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class Tokenizer
1818
unsigned char *cur_line;
1919
unsigned int line_num;
2020
unsigned char *string_start;
21+
uint32_t prev_loc;
2122

2223
int last_token=-1;
2324

@@ -34,7 +35,7 @@ class Tokenizer
3435
public:
3536
// Set the string to tokenize. The caller must ensure `str` will stay valid
3637
// as long as `lex` is being called.
37-
void set_string(const std::string &str);
38+
void set_string(const std::string &str, uint32_t prev_loc_);
3839

3940
// Get next token. Token ID is returned as function result, the semantic
4041
// value is put into `yylval`.
@@ -71,8 +72,8 @@ class Tokenizer
7172
// Return the current token's location
7273
void token_loc(Location &loc) const
7374
{
74-
loc.first = tok-string_start;
75-
loc.last = cur-string_start-1;
75+
loc.first = prev_loc + (tok-string_start);
76+
loc.last = prev_loc + (cur-string_start-1);
7677
}
7778

7879
void record_paren(Location &loc, char c);

src/lpython/parser/tokenizer.re

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,15 @@ void lex_imag(Allocator &al, const unsigned char *s,
122122
}
123123
}
124124

125-
void Tokenizer::set_string(const std::string &str)
125+
void Tokenizer::set_string(const std::string &str, uint32_t prev_loc_)
126126
{
127127
// The input string must be NULL terminated, otherwise the tokenizer will
128128
// not detect the end of string. After C++11, the std::string is guaranteed
129129
// to end with \0, but we check this here just in case.
130130
LFORTRAN_ASSERT(str[str.size()] == '\0');
131131
cur = (unsigned char *)(&str[0]);
132132
string_start = cur;
133+
prev_loc = prev_loc_;
133134
cur_line = cur;
134135
line_num = 1;
135136
}
@@ -777,7 +778,7 @@ Result<std::vector<int>> tokens(Allocator &al, const std::string &input,
777778
std::vector<Location> *locations)
778779
{
779780
Tokenizer t;
780-
t.set_string(input);
781+
t.set_string(input, 0);
781782
std::vector<int> tst;
782783
int token = yytokentype::END_OF_FILE + 1; // Something different from EOF
783784
while (token != yytokentype::END_OF_FILE) {

0 commit comments

Comments
 (0)