Mercurial > projects > dang
diff src/basic/SourceLocation.d @ 206:d3c148ca429b
Major moving of files. all src now goes into src, all docs in docs.
author | Anders Johnsen <skabet@gmail.com> |
---|---|
date | Tue, 12 Aug 2008 18:14:56 +0200 |
parents | |
children | e0551773a005 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/basic/SourceLocation.d Tue Aug 12 18:14:56 2008 +0200 @@ -0,0 +1,145 @@ +module basic.SourceLocation; + +/// Shorter alias for SourceLocation +public alias SourceLocation SLoc; + +/// SourceLocation points to a place in some buffer +struct SourceLocation +{ + /// Returns true, if the location is from a real file + bool isReal() { return (val & 0x80_00_00_00) == 0; } + /// Returns true, if the location is not from a real file + bool isVirtual() { return (val & 0x80_00_00_00) != 0; } + + /// Check if this location is invalid or not + bool isValid() { return val != uint.max; } + /// ditto + bool isInvalid() { return val == uint.max; } + + /** + Extracts the file id. + + Warning: In release mode this may return junk, if the loc is not from a + file + **/ + uint fileID() { + assert(isValid, "Location is invalid"); + assert(isReal, "You can only extract fileID from a real location"); + // Here we can rely on two facts, first that the high bit is zero + // since its a real position, second that FileOffset is saved in the + // high end, so all we need is some shifting + return val >> Bits.FileOffset; + } + + /** + Extracts the offset into the "file". (actually in to the referenced + chunk) + + Warning: In release mode this may return junk, if the loc is not from a + file + **/ + uint fileOffset() { + assert(isValid, "Location is invalid"); + assert(isReal, "You can only extract fileOffset from real locations"); + // FileOffset is stored in the lower bits, so all that is needed is a + // binary and with all ones in the lower bits. + return val & (1 << Bits.FileOffset) - 1; + } + + /// Get a new location, placed n bytes after the given location + SourceLocation opAdd(int n) + { + SourceLocation res = *this; + res.val += n; + return res; + } + + /// Get a new location, placed n bytes before the given location + SourceLocation opSub(int n) + { + SourceLocation res = *this; + res.val -= n; + return res; + } + + /// Creates a SourceLocation from a File ID + static SourceLocation fromFileID(uint fileID) + { + assert(fileID < Bits.MaxFileID, "To large fileID"); + SourceLocation res; + res.val = fileID << Bits.FileOffset; + return res; + } + + /** + Used for invalid/unknown locations. (also the default value, but this is + more explicit) + **/ + static const SourceLocation Invalid = {val: uint.max}; + +private: + /** + A SourceLocation consists of 1 bit, indicating real or virtual, meaning + if the location points to a file(real), a string mixin or has been + affected by #line(virtual). That information is saved in the most + significant bit. + The rest depends on which type we are dealing with. + Real: + 13 bits for a file identifier + 18 bits for offset into that "file" (one file may be split) + Virtual: + Unknown for now. Likely skewed toward more ids and some meta data + An invalid location is uint.max, this might happen by accident but its + unlikely. + **/ + uint val = uint.max; + + /** + This enum contains some constants that are useful for manipulating + SourceLocation's, like the size of various “members” of val. + **/ + static enum Bits { + /// Number of bits used for the offset into file buffers + FileOffset = 18, + /// Number of bits used to identify which file buffer this is from + FileID = 31 - FileOffset, + + /// Indicates how much can be indexed within one block(2^FileOffset) + MaxFileOffset = 1 << FileOffset, + MaxFileID = 1 << FileID, + } +} + +/// A simple pair used to describe a range in a buffer and not just a point. +struct SourceRange +{ + SourceLocation begin, end; + + static SourceRange opCall(SourceLocation loc) + { + return SourceRange(loc, loc + 1); + } + + static SourceRange opCall(SourceLocation begin, SourceLocation end) + { + SourceRange res; + res.begin = begin; + res.end = end; + return res; + } + + bool isValid() { return begin.isValid && end.isValid; } + bool isInvalid() { return begin.isInvalid || end.isInvalid; } + + bool isReal() { return begin.isReal && end.isReal; } + + /// Get a new range spanning both ranges + SourceRange opAdd(SourceRange that) + { + assert(this.isValid && that.isValid, "Invalid range"); + return SourceRange( + this.begin.val < that.begin.val? this.begin : that.begin, + this.end.val > that.end.val? this.end : that.end); + } +} +