Skip to content

Commit 287c555

Browse files
committed
Process output dignostic line by line.
1 parent ea76377 commit 287c555

File tree

3 files changed

+95
-66
lines changed

3 files changed

+95
-66
lines changed

src/source/location.d

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -260,16 +260,13 @@ public:
260260
return sourceManager.getFileID(this).getSource(context);
261261
}
262262

263-
auto getStartOfLine() {
264-
return sourceManager.getStartOfLine(this).getFullPosition(context);
265-
}
266-
267263
uint getLineNumber() {
268264
return sourceManager.getLineNumber(this);
269265
}
270266

271267
uint getColumn() {
272-
return Location(getStartOfLine(), this).length;
268+
auto line = getSource().getLineOffset(getLineNumber());
269+
return Location(line, this).length;
273270
}
274271

275272
uint getSourceOffset() {

src/source/manager.d

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,17 @@ public:
3535
}
3636

3737
FullPosition getWithOffset(uint offset) {
38-
auto p = sourceManager.getBase(this).getFullPosition(context)
39-
.getWithOffset(offset);
38+
auto p = sourceManager.getBase(this).getWithOffset(offset)
39+
.getFullPosition(context);
40+
41+
assert(p.getSource() == this, "Position overflow!");
42+
return p;
43+
}
44+
45+
FullPosition getLineOffset(uint line) {
46+
auto e = &sourceManager.getSourceEntry(this);
47+
auto p = e.base.getWithOffset(e.getLineOffset(line))
48+
.getFullPosition(context);
4049

4150
assert(p.getSource() == this, "Position overflow!");
4251
return p;
@@ -122,13 +131,6 @@ public:
122131
return p.isFile() ? files.getFileID(p) : mixins.getFileID(p);
123132
}
124133

125-
Position getStartOfLine(Position p) {
126-
auto e = &getSourceEntry(p);
127-
auto b = e.base;
128-
auto o = Location(b, p).length;
129-
return b.getWithOffset(e.getLineOffset(o));
130-
}
131-
132134
uint getLineNumber(Position p) {
133135
auto e = &getSourceEntry(p);
134136
auto o = Location(e.base, p).length;
@@ -375,11 +377,11 @@ private:
375377
lastLineLookup = lookup!(l => l, 15)(lines, index, lastLineLookup);
376378
}
377379

378-
return lastLineLookup + 1;
380+
return lastLineLookup;
379381
}
380382

381-
uint getLineOffset(uint index) out(result; result <= index) {
382-
return lines[getLineNumber(index) - 1];
383+
uint getLineOffset(uint line) in(line <= lines.length) {
384+
return (line == lines.length) ? cast(uint) content.length : lines[line];
383385
}
384386

385387
bool isIndexInLine(uint index, uint line) {

src/util/terminal.d

Lines changed: 79 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -13,77 +13,107 @@ void outputCaretDiagnostics(FullLocation location, string fixHint) {
1313
auto source = location.getSource();
1414
auto content = source.getContent();
1515

16-
auto offset = location.getStartOffset();
17-
if (offset >= content.length) {
18-
offset = cast(uint) content.length - 1;
16+
auto first = location.getStartOffset();
17+
if (first >= content.length) {
18+
/**
19+
* This typically happens when the input ends unexpectedly.
20+
* In this situation, we want to display the last line of the input
21+
* and put the carret at the end of that line.
22+
*/
23+
first = cast(uint) content.length - 1;
1924
}
2025

21-
auto indexPosition = source.getWithOffset(offset);
22-
uint start = indexPosition.getStartOfLine().getSourceOffset();
26+
auto startp = source.getWithOffset(first);
27+
auto nline = startp.getLineNumber();
28+
uint current = source.getLineOffset(nline).getSourceOffset();
2329

24-
uint end = location.getStopOffset();
30+
uint column = first - current;
31+
assert(column == startp.getColumn());
2532

26-
// This is unexpected end of input.
27-
if (end > content.length) {
28-
end = cast(uint) content.length;
29-
}
33+
stderr.write(location.isMixin() ? "mixin" : source.getFileName().toString(),
34+
":", nline + 1, ":", column, ":");
3035

31-
// Trim end of line if apropriate.
32-
while (end > start) {
33-
end--;
36+
stderr.writeColouredText(ConsoleColour.Red, " error: ");
37+
stderr.writeColouredText(ConsoleColour.White, fixHint, "\n");
3438

35-
auto c = content[end];
36-
if (c != '\r' && c != '\n') {
37-
end++;
38-
break;
39-
}
39+
uint last = location.getStopOffset();
40+
if (last > content.length) {
41+
/**
42+
* FIXME: I'm pretty sure we should consider this happening a bug.
43+
* As far as I'm aware, the only case it is happening is when
44+
* we generate an End token in the lexer, and we could make
45+
* it zero length and avoid this special case.
46+
*/
47+
last = cast(uint) content.length;
4048
}
4149

42-
// Extend the range up to the end of the line.
43-
while (end < content.length) {
44-
auto c = content[end];
45-
if (c == '\r' || c == '\n') {
46-
break;
47-
}
50+
while (current < last) {
51+
uint next = source.getLineOffset(++nline).getSourceOffset();
52+
scope(success) current = next;
4853

49-
end++;
50-
}
54+
// Trim end of line if apropriate.
55+
uint end = backTrackLineBreak(content, next);
56+
auto line = content[current .. end];
5157

52-
auto line = content[start .. end];
58+
auto c = current < first ? first - current : 0;
59+
auto length = end > last ? last - current : line.length;
5360

54-
uint index = offset - start;
55-
uint length = location.length;
61+
char[] underline;
62+
underline.length = length;
5663

57-
// Multi line location.
58-
if (index < line.length && index + length > line.length) {
59-
length = cast(uint) line.length - index;
60-
}
64+
foreach (i; 0 .. c) {
65+
underline[i] = (line[i] == '\t') ? '\t' : ' ';
66+
}
67+
68+
auto printCarret = current <= first;
69+
if (printCarret) {
70+
underline[c] = '^';
71+
}
72+
73+
foreach (i; c + printCarret .. length) {
74+
underline[i] = '~';
75+
}
6176

62-
char[] underline;
63-
underline.length = index + length;
64-
foreach (i; 0 .. index) {
65-
underline[i] = (line[i] == '\t') ? '\t' : ' ';
77+
stderr.writeln(line);
78+
stderr.writeColouredText(ConsoleColour.Green, underline, "\n");
6679
}
6780

68-
underline[index] = '^';
69-
foreach (i; index + 1 .. index + length) {
70-
underline[i] = '~';
81+
if (location.isMixin()) {
82+
outputCaretDiagnostics(source.getImportLocation(), "mixed in at");
7183
}
84+
}
7285

73-
assert(index == indexPosition.getColumn());
86+
template LineBreaksOfLength(uint N) {
87+
import source.lexwhitespace;
88+
import std.array, std.algorithm;
89+
enum LineBreaksOfLength = LineBreaks.filter!(op => op.length == N).array();
90+
}
7491

75-
stderr.write(location.isMixin() ? "mixin" : source.getFileName().toString(),
76-
":", indexPosition.getLineNumber(), ":", index, ":");
92+
uint backTrackLineBreak(string content, uint index)
93+
in(index <= content.length && content.length < uint.max) {
94+
if (index >= 2) {
95+
auto b = content[index - 1];
96+
auto a = content[index - 2];
7797

78-
stderr.writeColouredText(ConsoleColour.Red, " error: ");
79-
stderr.writeColouredText(ConsoleColour.White, fixHint, "\n");
98+
static foreach (op; LineBreaksOfLength!2) {
99+
if (a == op[0] && b == op[1]) {
100+
return index - 2;
101+
}
102+
}
103+
}
80104

81-
stderr.writeln(line);
82-
stderr.writeColouredText(ConsoleColour.Green, underline, "\n");
105+
if (index >= 1) {
106+
auto c = content[index - 1];
83107

84-
if (location.isMixin()) {
85-
outputCaretDiagnostics(source.getImportLocation(), "mixed in at");
108+
static foreach (op; LineBreaksOfLength!1) {
109+
if (c == op[0]) {
110+
return index - 1;
111+
}
112+
}
86113
}
114+
115+
// No match.
116+
return index;
87117
}
88118

89119
/**

0 commit comments

Comments
 (0)