Skip to content

Commit 13d6b40

Browse files
committed
Use line directives to when computing line numbers.
1 parent ab2be72 commit 13d6b40

File tree

4 files changed

+99
-28
lines changed

4 files changed

+99
-28
lines changed

src/d/semantic/expression.d

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,22 @@ struct ExpressionVisitor {
6363
return new ConstantExpression(e.location, new StringConstant(e.value));
6464
}
6565

66+
Expression visit(__File__Literal e) {
67+
auto location = e.location;
68+
auto dloc = location.start.getFullPosition(context).getDebugLocation();
69+
70+
return new ConstantExpression(
71+
location, new StringConstant(dloc.filename.toString(context)));
72+
}
73+
74+
Expression visit(__Line__Literal e) {
75+
auto location = e.location;
76+
auto dloc = location.start.getFullPosition(context).getDebugLocation();
77+
78+
return new ConstantExpression(
79+
location, new IntegerConstant(dloc.line, BuiltinType.Int));
80+
}
81+
6682
private:
6783
ErrorExpression getError(T...)(T ts, Location location, string msg) {
6884
return .getError(ts, location, msg).expression;

src/source/location.d

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ module source.location;
22

33
import source.context;
44

5-
// Line directives aren't fully implemented, so this is false by default.
6-
enum EnableLineDirectiveByDefault = false;
7-
85
/**
96
* Struct representing a location in a source file.
107
* Effectively a pair of Position within the source file.
@@ -251,9 +248,7 @@ public:
251248
return position.getWithOffsets(start, stop).getFullLocation(context);
252249
}
253250

254-
auto getDebugLocation(
255-
bool useLineDirective = EnableLineDirectiveByDefault
256-
) {
251+
auto getDebugLocation(bool useLineDirective = true) {
257252
return sourceManager.getDebugLocation(this, useLineDirective);
258253
}
259254

src/source/manager.d

Lines changed: 67 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -72,21 +72,60 @@ package:
7272

7373
struct LineDirectives {
7474
struct LineEntry {
75-
Position position;
75+
uint offset;
76+
uint sline;
7677
Name filename;
7778
uint line;
7879
}
7980

80-
LineEntry[] lineDirectives;
81+
LineEntry[] lineEntries;
82+
uint lastLineEntry;
8183

82-
this(Position p, Name filename, uint line) {
83-
lineDirectives = [LineEntry(p, filename, line)];
84+
this(Name filename) {
85+
lineEntries = [LineEntry(0, 0, filename, 1)];
8486
}
8587

86-
void registerLineDirective(Position p, Name filename, uint line) {
87-
if (lineDirectives[$ - 1].position < p) {
88-
lineDirectives ~= LineEntry(p, filename, line);
88+
ref
89+
LineDirectives registerLineDirective(uint offset, uint sline, Name filename,
90+
uint line) in(lineEntries.length > 0) {
91+
auto previous = lineEntries[$ - 1];
92+
assert(previous.offset < offset,
93+
"Line directives must be register in order!");
94+
95+
/**
96+
* FIXME: We need to diferentiate in between the case where no
97+
* filename is supplied and the case where it is explicitely
98+
* set as an empty string.
99+
*/
100+
if (filename == BuiltinName!"") {
101+
filename = previous.filename;
102+
}
103+
104+
lineEntries ~= LineEntry(offset, sline, filename, line);
105+
return this;
106+
}
107+
108+
auto findNearestLineEntry(uint offset) {
109+
if (!isOffsetInEntry(offset, lastLineEntry)) {
110+
import source.util.lookup;
111+
lastLineEntry =
112+
lookup!(e => e.offset, 8)(lineEntries, offset, lastLineEntry);
89113
}
114+
115+
return lineEntries[lastLineEntry];
116+
}
117+
118+
bool isOffsetInEntry(uint offset, uint entry) {
119+
auto entryOffset = lineEntries[entry].offset;
120+
if (offset < entryOffset) {
121+
return false;
122+
}
123+
124+
if (offset == entryOffset || entry + 1 == lineEntries.length) {
125+
return true;
126+
}
127+
128+
return offset < lineEntries[entry + 1].offset;
90129
}
91130
}
92131

@@ -106,7 +145,7 @@ public:
106145
Location location,
107146
Name filename,
108147
Name directory,
109-
string content
148+
string content,
110149
) out(result; result.isFile()) {
111150
return files
112151
.registerFileZeroTerminated(location, filename, directory, content);
@@ -137,10 +176,7 @@ public:
137176
return e.getLineNumber(o);
138177
}
139178

140-
DebugLocation getDebugLocation(
141-
Position p,
142-
bool useLineDirective = EnableLineDirectiveByDefault
143-
) {
179+
DebugLocation getDebugLocation(Position p, bool useLineDirective = true) {
144180
// Find an actual file.
145181
while (p.isMixin()) {
146182
p = getImportLocation(getFileID(p)).start;
@@ -150,26 +186,35 @@ public:
150186
auto e = &getSourceEntry(id);
151187
auto o = Location(e.base, p).length;
152188

153-
auto filename = e.filename;
154189
auto line = e.getLineNumber(o);
155-
auto column = o - e.getLineOffset(line);
190+
auto column = o - e.getLineOffset(line) + 1;
156191

157-
if (useLineDirective && e.hasLineDirectives) {
158-
assert(0, "Line directive not supported!");
192+
if (!useLineDirective || !e.hasLineDirectives) {
193+
return DebugLocation(e.filename, line + 1, column);
159194
}
160195

161-
return DebugLocation(filename, line + 1, column + 1);
196+
auto lds = lineDirectives[id];
197+
auto lde = lds.findNearestLineEntry(o);
198+
199+
line += lde.line;
200+
line -= lde.sline;
201+
202+
return DebugLocation(lde.filename, line, column);
162203
}
163204

164205
void registerLineDirective(Position p, Name filename, uint line) {
165206
auto id = getFileID(p);
207+
auto e = &getSourceEntry(id);
208+
auto o = Location(e.base, p).length;
209+
auto sline = e.getLineNumber(o);
166210

167-
getSourceEntry(id).hasLineDirectives = true;
211+
e.hasLineDirectives = true;
168212
lineDirectives.update(
169213
id,
170-
() => LineDirectives(p, filename, line),
214+
() => LineDirectives(e.filename)
215+
.registerLineDirective(o, sline, filename, line),
171216
(ref LineDirectives ds) =>
172-
ds.registerLineDirective(p, filename, line)
217+
ds.registerLineDirective(o, sline, filename, line)
173218
);
174219
}
175220

@@ -364,12 +409,12 @@ public:
364409
}
365410

366411
@property
367-
auto filename() const in(base.isFile()) {
412+
Name filename() const in(base.isFile()) {
368413
return _filename;
369414
}
370415

371416
@property
372-
auto directory() const in(base.isFile()) {
417+
Name directory() const in(base.isFile()) {
373418
return _directory;
374419
}
375420

test/unit/line.d

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#line 100
2+
enum FirstLine = __LINE__;
3+
4+
unittest line {
5+
assert(FirstLine == 100);
6+
7+
#line 200
8+
assert(__LINE__ == 200);
9+
assert(__LINE__ == 201);
10+
11+
#line // Comment...
12+
300
13+
assert(__LINE__ == 300);
14+
assert(__LINE__ == 301);
15+
}

0 commit comments

Comments
 (0)