view src/basic/SourceLocation.d @ 207:e0551773a005

Added the correct version.
author Anders Johnsen <skabet@gmail.com>
date Tue, 12 Aug 2008 18:19:34 +0200
parents d3c148ca429b
children
line wrap: on
line source

module basic.SourceLocation;

import Integer = tango.text.convert.Integer;

/// 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;
    }

    /// Get the length between two location
    int opSub(SourceLocation loc)
    {
        return val - loc.val;
    }

    /// 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;
    }

    char[] toString()
    {
        return Integer.toString(val);
    }
    /**
      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);
    }
}