Skip to content

Commit ff8875b

Browse files
committed
add missing file dmdlocation.d
1 parent e4cf83c commit ff8875b

File tree

1 file changed

+353
-0
lines changed

1 file changed

+353
-0
lines changed

vdc/dmdserver/dmdlocation.d

Lines changed: 353 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,353 @@
1+
// replace dmd.location for faster line/file lookup and incremental updates
2+
3+
module dmd.location;
4+
5+
import core.stdc.stdio;
6+
7+
import dmd.common.outbuffer;
8+
import dmd.root.array;
9+
import dmd.root.filename;
10+
import dmd.root.rmem : xarraydup;
11+
import dmd.root.string: toDString;
12+
import dmd.root.stringtable;
13+
14+
/// How code locations are formatted for diagnostic reporting
15+
enum MessageStyle : ubyte
16+
{
17+
digitalmars, /// filename.d(line): message
18+
gnu, /// filename.d:line: message, see https://www.gnu.org/prep/standards/html_node/Errors.html
19+
sarif /// JSON SARIF output, see https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html
20+
}
21+
/**
22+
A source code location
23+
24+
Used for error messages, `__FILE__` and `__LINE__` tokens, `__traits(getLocation, XXX)`,
25+
debug info etc.
26+
*/
27+
struct Loc
28+
{
29+
private ulong data = 0; // bitfield of file, line and column
30+
31+
static immutable Loc initial; /// use for default initialization of Loc's
32+
33+
extern (C++) __gshared bool showColumns;
34+
extern (C++) __gshared MessageStyle messageStyle;
35+
36+
nothrow:
37+
/*******************************
38+
* Configure how display is done
39+
* Params:
40+
* showColumns = when to display columns
41+
* messageStyle = digitalmars or gnu style messages
42+
*/
43+
extern (C++) static void set(bool showColumns, MessageStyle messageStyle)
44+
{
45+
this.showColumns = showColumns;
46+
this.messageStyle = messageStyle;
47+
}
48+
49+
/// Returns: a Loc that simply holds a filename, with no line / column info
50+
extern (C++) static Loc singleFilename(const char* filename)
51+
{
52+
return singleFilename(filename.toDString);
53+
}
54+
55+
/// Returns: a Loc that simply holds a filename, with no line / column info
56+
static Loc singleFilename(const(char)[] filename)
57+
{
58+
ulong fileIndex = toLocFileIndex(filename);
59+
return Loc((fileIndex << 48) | 1); // default to charnum 1
60+
}
61+
62+
/// utf8 code unit index relative to start of line, starting from 1
63+
extern (C++) uint charnum() const @nogc @safe
64+
{
65+
return data & 0xffff;
66+
}
67+
68+
/// line number, starting from 1
69+
extern (C++) uint linnum() const @nogc @trusted
70+
{
71+
return (data >> 16) & 0xffff_ffff;
72+
}
73+
74+
/***
75+
* Returns: filename for this location, null if none
76+
*/
77+
extern (C++) const(char)* filename() const @nogc
78+
{
79+
return locFileName[data >> 48].ptr;
80+
}
81+
82+
/// Advance this location to the first column of the next line
83+
void nextLine() @safe pure @nogc
84+
{
85+
data = (data & ~0xffffL) + 0x10001;
86+
}
87+
88+
bool isValid() const pure @safe
89+
{
90+
return data != 0;
91+
}
92+
93+
extern (C++) const(char)* toChars(bool showColumns = Loc.showColumns,
94+
MessageStyle messageStyle = Loc.messageStyle) const nothrow
95+
{
96+
return SourceLoc(this).toChars(showColumns, messageStyle);
97+
}
98+
/**
99+
* Checks for equivalence by comparing the filename contents (not the pointer) and character location.
100+
*
101+
* Note:
102+
* - Uses case-insensitive comparison on Windows
103+
* - Ignores `charnum` if `Columns` is false.
104+
*/
105+
extern (C++) bool equals(Loc loc) const
106+
{
107+
auto this_data = showColumns ? data : data & ~0xffff;
108+
auto loc_data = showColumns ? loc.data : loc.data & ~0xffff;
109+
return this_data == loc_data;
110+
}
111+
112+
/**
113+
* `opEquals()` / `toHash()` for AA key usage
114+
*
115+
* Compare filename contents (case-sensitively on Windows too), not
116+
* the pointer - a static foreach loop repeatedly mixing in a mixin
117+
* may lead to multiple equivalent filenames (`foo.d-mixin-<line>`),
118+
* e.g., for test/runnable/test18880.d.
119+
*/
120+
extern (D) bool opEquals(ref const(Loc) loc) const @trusted nothrow @nogc
121+
{
122+
return this.data == loc.data;
123+
}
124+
125+
/// ditto
126+
extern (D) size_t toHash() const @trusted nothrow
127+
{
128+
return hashOf(this.data);
129+
}
130+
}
131+
132+
/**
133+
* Format a source location for error messages
134+
*
135+
* Params:
136+
* buf = buffer to write string into
137+
* loc = source location to write
138+
* showColumns = include column number in message
139+
* messageStyle = select error message format
140+
*/
141+
void writeSourceLoc(ref OutBuffer buf, SourceLoc loc, bool showColumns, MessageStyle messageStyle) nothrow
142+
{
143+
auto filename = loc.filename;
144+
if (filename is null)
145+
return;
146+
buf.writestring(loc.filename);
147+
if (loc.linnum == 0)
148+
return;
149+
150+
final switch (messageStyle)
151+
{
152+
case MessageStyle.digitalmars:
153+
buf.writeByte('(');
154+
buf.print(loc.linnum);
155+
if (showColumns && loc.charnum)
156+
{
157+
buf.writeByte(',');
158+
buf.print(loc.charnum);
159+
}
160+
buf.writeByte(')');
161+
break;
162+
case MessageStyle.gnu: // https://www.gnu.org/prep/standards/html_node/Errors.html
163+
buf.writeByte(':');
164+
buf.print(loc.linnum);
165+
if (showColumns && loc.charnum)
166+
{
167+
buf.writeByte(':');
168+
buf.print(loc.charnum);
169+
}
170+
break;
171+
case MessageStyle.sarif: // https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html
172+
// No formatting needed here for SARIF
173+
break;
174+
}
175+
}
176+
177+
// Global string table to make file names comparable via `is`
178+
private __gshared StringTable!(size_t) locFileNameIndex;
179+
private __gshared const(char)[][] locFileName;
180+
181+
size_t toLocFileIndex(const(char)[] fname) nothrow @trusted
182+
{
183+
if (locFileName.length == 0)
184+
{
185+
locFileNameIndex.reset();
186+
locFileName ~= null;
187+
locFileNameIndex.insert("", 0); // for loc.initial
188+
}
189+
if (auto p = locFileNameIndex.lookup(fname))
190+
return p.value;
191+
size_t idx = locFileName.length;
192+
locFileName ~= fname.xarraydup;
193+
locFileNameIndex.insert(fname, idx);
194+
return idx;
195+
}
196+
197+
const(char)[] toLocFilename(const(char)[] fname) nothrow
198+
{
199+
return locFileName[toLocFileIndex(fname)];
200+
}
201+
202+
const(char)[] toLocFilename(const(char)* fname) nothrow
203+
{
204+
return toLocFilename(fname.toDString);
205+
}
206+
207+
void location_init()
208+
{
209+
locFileName = null;
210+
locFileNameIndex.reset();
211+
}
212+
213+
struct SourceLoc
214+
{
215+
Loc loc;
216+
217+
//alias loc this;
218+
219+
// aliases for backwards compatibility
220+
alias linnum = loc.linnum;
221+
alias line = loc.linnum;
222+
alias charnum = loc.charnum;
223+
alias column = loc.charnum;
224+
225+
this(Loc oloc) nothrow @safe
226+
{
227+
loc = oloc;
228+
}
229+
230+
this(const(char)[] filename, uint line, uint column,
231+
uint fileOffset = 0, const(char)[] fileContent = null) nothrow @safe
232+
{
233+
if (column > 0xffff)
234+
column = 0xffff;
235+
ulong fileIndex = toLocFileIndex(filename);
236+
loc.data = (fileIndex << 48) | (line << 16) | column;
237+
}
238+
239+
void filename(const(char)[] fname) nothrow
240+
{
241+
ulong fileIndex = toLocFileIndex(fname);
242+
loc.data = (loc.data & ((1L << 48) - 1)) | (fileIndex << 48);
243+
}
244+
const(char)[] filename() const nothrow @nogc
245+
{
246+
return loc.filename.toDString;
247+
}
248+
uint xline() const nothrow
249+
{
250+
return loc.linnum();
251+
}
252+
uint xcolumn() const nothrow
253+
{
254+
return loc.charnum();
255+
}
256+
const(char)[] fileContent() const nothrow
257+
{
258+
return null; // only for error messages with context
259+
}
260+
uint fileOffset() const nothrow
261+
{
262+
return 0; // only for error messages with context
263+
}
264+
265+
bool opEquals(SourceLoc other) const nothrow
266+
{
267+
return loc == other.loc;
268+
}
269+
270+
extern (C++) const(char)* toChars(bool showColumns = Loc.showColumns,
271+
MessageStyle messageStyle = Loc.messageStyle) const nothrow
272+
{
273+
OutBuffer buf;
274+
writeSourceLoc(buf, this, showColumns, messageStyle);
275+
return buf.extractChars();
276+
}
277+
}
278+
279+
struct BaseLoc
280+
{
281+
SourceLoc loc;
282+
283+
uint startLine;
284+
uint startOffset;
285+
uint lastLineOffset;
286+
BaseLoc[] substitutions; /// Substitutions from #line / #file directives
287+
288+
alias loc this;
289+
290+
nothrow:
291+
this(const(char)[] filename, uint startLine)
292+
{
293+
this.loc = SourceLoc(filename, 1, 1);
294+
this.startLine = startLine;
295+
}
296+
297+
Loc getLoc(uint offset) @nogc
298+
{
299+
Loc nloc;
300+
nloc.data = loc.loc.data + offset - lastLineOffset; // add char offset
301+
return nloc;
302+
}
303+
304+
/**
305+
* Register a new file/line mapping from #file and #line directives
306+
* Params:
307+
* offset = byte offset in the source file at which the substitution starts
308+
* filename = new filename from this point on (null = unchanged)
309+
* line = line number from this point on
310+
*/
311+
void addSubstitution(uint offset, const(char)* filename, uint line) @system
312+
{
313+
auto fname = filename.toDString;
314+
if (substitutions.length == 0)
315+
substitutions ~= BaseLoc(this.filename, 0);
316+
317+
if (fname.length == 0)
318+
fname = substitutions[$ - 1].filename;
319+
substitutions ~= BaseLoc(fname, startLine + line); // cast(int) (line - lines.length + startLine - 2));
320+
}
321+
322+
/// Returns: `loc` modified by substitutions from #file / #line directives
323+
SourceLoc substitute(SourceLoc loc)
324+
{
325+
if (substitutions.length == 0)
326+
return loc;
327+
328+
const i = 0; // todo: getSubstitutionIndex(loc.fileOffset);
329+
if (substitutions[i].filename.length > 0)
330+
loc.filename = substitutions[i].filename;
331+
return SourceLoc(loc.filename, loc.line + substitutions[i].startLine, loc.column);
332+
}
333+
void newLine(uint offset) @safe
334+
{
335+
lastLineOffset = offset;
336+
loc.loc.nextLine();
337+
}
338+
}
339+
340+
BaseLoc* newBaseLoc(const(char)* filename, const(char)[] fileContent) nothrow
341+
{
342+
return new BaseLoc(filename.toDString, 0);
343+
}
344+
345+
// for a language server, lowered expression should not reuse the original source location
346+
// as internal names might get exposed to the user
347+
ref const(Loc) loweredLoc(return ref const Loc loc)
348+
{
349+
version(LanguageServer)
350+
return Loc.initial;
351+
else
352+
return loc;
353+
}

0 commit comments

Comments
 (0)