@@ -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