/*
Ousía
Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
/**
* @file Location.hpp
*
* Types used for describing positions, ranges and excerpts of source files used
* for describing log messages.
*
* @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
*/
#ifndef _OUSIA_LOCATION_HPP_
#define _OUSIA_LOCATION_HPP_
#include
#include
#include
#include
namespace ousia {
/**
* Type used for referencing a source file currently opened in a Project.
*/
using SourceId = uint16_t;
/**
* Maximum value for a SourceId. Indicates invalid entries.
*/
constexpr SourceId InvalidSourceId = std::numeric_limits::max();
/**
* Type used for specifying an offset within a source file.
*/
using SourceOffset = uint32_t;
/**
* Maximum value for a SourceOffset. As SourceOffset is a 32 Bit unsigned
* integer, the maximum value is 2^32-1, which means that 4 GiB are addressable
* by SourceOffset.
*/
constexpr SourceOffset InvalidSourceOffset =
std::numeric_limits::max();
/**
* Function for clamping a size_t to a valid SourceOffset value.
*
* @param pos is the size_t value that should be converted to a SourceOffset
* value. If pos is larger than the maximum value that can be represented by
* SourceOffset, the result is set to this maximum value, which is interpreted
* as "invalid" by functions dealing with the SourceOffset type.
* @return the clamped position value.
*/
inline SourceOffset clampToSourcePosition(size_t pos)
{
return pos > InvalidSourceOffset ? InvalidSourceOffset : pos;
}
/**
* Class specifying a position within an (unspecified) source file.
*/
class SourcePosition {
private:
/**
* Offset position in bytes relative to the start of the document.
*/
SourceOffset pos;
public:
/**
* Default constructor of the SourcePosition class. Sets the position to
* InvalidSourceOffset and thus marks the SourcePosition as invalid.
*/
SourcePosition() : pos(InvalidSourceOffset) {}
/**
* Creates a new SourcePosition instance with the given byte offset.
*/
SourcePosition(size_t pos) : pos(clampToSourcePosition(pos)) {}
/**
* Sets the position of the SourcePosition value to the given value. Clamps
* the given size_t to the valid range.
*
* @param pos is the position value that should be set.
*/
void setPosition(size_t pos) { this->pos = clampToSourcePosition(pos); }
/**
* Returns the position value. Only use the value if "valid" returns true.
*
* @return the current position.
*/
SourceOffset getPosition() const { return pos; }
/**
* Returns true if the source position is valid, false otherwise. Invalid
* positions are set to the maximum representable number.
*
* @return true if the SourcePosition instance is value, false otherwise.
*/
bool isValid() const { return pos != InvalidSourceOffset; }
};
/**
* The SourceRange class represents a range within an (unspecified) source file.
*/
class SourceRange {
private:
/**
* Start byte offset.
*/
SourcePosition start;
/**
* End byte offset.
*/
SourcePosition end;
public:
/**
* Default constructor. Creates an invalid range.
*/
SourceRange(){};
/**
* Constructor for a zero-length range.
*
* @param pos is the byte offset at which the SourceRange instance should be
* located.
*/
SourceRange(SourcePosition pos) : start(pos), end(pos) {}
/**
* Constructor of a SourceRange instance.
*
* @param start is the byte offset of the first character in the range
* (start is inclusive).
* @param end points at the end of the range (end is non-inclusive).
*/
SourceRange(SourcePosition start, SourcePosition end)
: start(start), end(end)
{
}
/**
* Sets the start of the SourceRange value to the given value. This
* operation might render the SourceRange invalid (if the given position is
* larger than the end position).
*
* @param pos is the start position value that should be set.
*/
void setStart(SourcePosition pos) { this->start = pos; }
/**
* Sets the end of the SourceRange value to the given value. This operation
* might render the SourceRange invalid (if the given position is smaller
* than the start position).
*
* @param pos is the end position that should be set.
*/
void setEnd(SourcePosition pos) { this->end = pos; }
/**
* Sets the start and end of the SourceRange value to the given values.
* This operation might render the SourceRange invalid (if the given end
* position is smaller than the start position).
*
* @param start is the start position that should be set.
* @param end is the end position that should be set.
*/
void setRange(SourcePosition start, SourcePosition end)
{
this->start = start;
this->end = end;
}
/**
* Makes the Range represent a zero-length range that is located at the
* given position. The given position should be interpreted as being located
* "between the character just before the start offset and the start
* offset".
*
* @param pos is the position to which start and end should be set.
*/
void setPosition(SourcePosition pos)
{
this->start = pos;
this->end = pos;
}
/**
* Returns the start position of the SourceRange instance.
*
* @return the start offset in bytes.
*/
SourceOffset getStart() const { return start.getPosition(); }
/**
* Returns the end position of the SourceRange instance.
*
* @return the end offset in bytes (non-inclusive).
*/
SourceOffset getEnd() const { return end.getPosition(); }
/**
* Returns a copy of the underlying SourcePosition instance representing the
* start position.
*
* @return a copy of the start SourcePosition instance.
*/
SourcePosition getStartPosition() const { return start; }
/**
* Returns a copy of the underlying SourcePosition instance representing the
* end position.
*
* @return a copy of the end SourcePosition instance.
*/
SourcePosition getEndPosition() const { return end; }
/**
* Returns the length of the range. A range may have a zero value length, in
* which case it should be interpreted as "between the character before
* the start offset and the start offset". The returned value is only valid
* if the isValid() method returns true!
*
* @return the length of the range in bytes.
*/
size_t getLength() const { return end.getPosition() - start.getPosition(); }
/**
* Returns true if this range is actually valid. This is the case if the
* start position is smaller or equal to the end position and start and end
* position themself are valid.
*
* @return true if the Range is valid.
*/
bool isValid() const
{
return start.isValid() && end.isValid() &&
start.getPosition() <= end.getPosition();
}
};
/**
* The SourceLocation class describes a range within a specific source file.
*/
class SourceLocation : public SourceRange {
private:
/**
* Id of the source file.
*/
SourceId sourceId;
public:
/**
* Default constructor.
*/
SourceLocation() : sourceId(InvalidSourceId){};
/**
* Constructor, binds the SourceLocation to the given source file.
*
* @param sourceId specifies the file this location refers to.
*/
SourceLocation(SourceId sourceId) : sourceId(sourceId){};
/**
* Constructor for a zero-length range.
*
* @param sourceId specifies the file this location refers to.
* @param pos is the byte offset at which the SourceRange instance should be
* located.
*/
SourceLocation(SourceId sourceId, SourcePosition pos)
: SourceRange(pos), sourceId(sourceId)
{
}
/**
* Constructor of a SourceRange instance.
*
* @param sourceId specifies the file this location refers to.
* @param start is the byte offset of the first character in the range
* (start is inclusive).
* @param end points at the end of the range (end is non-inclusive).
*/
SourceLocation(SourceId sourceId, SourcePosition start, SourcePosition end)
: SourceRange(start, end), sourceId(sourceId)
{
}
/**
* Constructor of a SourceRange instance.
*
* @param sourceId specifies the file this location refers to.
* @param start is the byte offset of the first character in the range
* (start is inclusive).
* @param end points at the end of the range (end is non-inclusive).
*/
SourceLocation(SourceId sourceId, const SourceRange &range)
: SourceRange(range), sourceId(sourceId)
{
}
/**
* Sets the source id to the given value.
*
* @param sourceId specifies the file this location refers to.
*/
void setSourceId(SourceId sourceId) { this->sourceId = sourceId; }
/**
* Returns the id of the source file this SourceLocation instance is bound
* to.
*
* @return the id of the source file this instance is bound to.
*/
SourceId getSourceId() const { return sourceId; }
/**
* Returns true if this location is actually valid. This is the case if
* the underlying range is valid and the source id is valid.
*
* @return true if the Range is valid.
*/
bool isValid() const
{
return SourceRange::isValid() && sourceId != InvalidSourceId;
}
/**
* Calls the getLocation function on the given reference.
*
* @param obj is the object on which the getLocation function should be
* called.
* @return the SourceLocation returned by the getLocation function.
*/
template
static SourceLocation location(const T &obj)
{
return obj.getLocation();
}
/**
* Calls the getLocation function on the given pointer.
*
* @param obj is the object on which the getLocation function should be
* called.
* @return the SourceLocation returned by the getLocation function.
*/
template
static SourceLocation location(const T *obj)
{
return obj->getLocation();
}
};
/**
* NullSourceLocation is an empty SourceLocation instance.
*/
extern const SourceLocation NullSourceLocation;
/**
* Represents the context of a SourceLocation instance. Used to build error
* messages.
*/
struct SourceContext {
/**
* Underlying source range (contains the byte start and end offsets in
* bytes).
*/
SourceRange range;
/**
* Name of the underlying resource.
*/
std::string filename;
/**
* Start line, starting with one.
*/
size_t startLine;
/**
* Start column, starting with one.
*/
size_t startColumn;
/**
* End line, starting with one.
*/
size_t endLine;
/**
* End column, starting with one.
*/
size_t endColumn;
/**
* Set to the content of the current line.
*/
std::string text;
/**
* Relative position (in characters) within that line. May point to
* locations beyond the text content.
*/
size_t relPos;
/**
* Relative length (in characters) within that line. May end beyond the
* text given in the context.
*/
size_t relLen;
/**
* Set to true if the beginning of the line has been truncated (because
* the reader position is too far away from the actual position of the
* line).
*/
bool truncatedStart;
/**
* Set to true if the end of the line has been truncated (because the
* reader position is too far away from the actual end position of the
* line.
*/
bool truncatedEnd;
/**
* Default constructor, initializes primitive members with zero values.
*/
SourceContext()
: startLine(0),
startColumn(0),
endLine(0),
endColumn(0),
relPos(0),
relLen(0),
truncatedStart(false),
truncatedEnd(false)
{
}
/**
* Returns true the context text is not empty.
*
* @return true if the context is valid and e.g. should be printed.
*/
bool isValid() const { return range.isValid() && hasLine() && hasColumn(); }
/**
* Returns true if a valid (non-empty) filename is set.
*/
bool hasFile() const { return !filename.empty(); }
/**
* Returns true if some valid context text is set.
*/
bool hasText() const { return !text.empty(); }
/**
* Returns true, if the start line number is valid, false otherwise.
*
* @return true for valid line numbers.
*/
bool hasLine() const { return startLine > 0; }
/**
* Returns true, if the start column number is valid, false otherwise.
*
* @return true for valid column numbers.
*/
bool hasColumn() const { return startColumn > 0; }
};
/**
* Callback used to lookup the context corresponding to the given source
* location.
*
* @param location is the location for which the context should be looked up.
* @return the corresponding SourceContext.
*/
using SourceContextCallback =
std::function;
/**
* Function to be used as default value for the SourceContextCallback. Returns
* an invalid SourceContext.
*
* @param location is the location for which the context should be looked up.
* @return an empty, invalid SourceContext.
*/
SourceContext NullSourceContextCallback(const SourceLocation &location);
}
#endif /* _OUSIA_LOCATION_HPP_ */