diff options
Diffstat (limited to 'src/core/common')
| -rw-r--r-- | src/core/common/Location.cpp | 23 | ||||
| -rw-r--r-- | src/core/common/Location.hpp | 399 | ||||
| -rw-r--r-- | src/core/common/Rtti.cpp | 11 | ||||
| -rw-r--r-- | src/core/common/Rtti.hpp | 11 | ||||
| -rw-r--r-- | src/core/common/Utils.cpp | 23 | ||||
| -rw-r--r-- | src/core/common/Utils.hpp | 20 | 
6 files changed, 428 insertions, 59 deletions
diff --git a/src/core/common/Location.cpp b/src/core/common/Location.cpp new file mode 100644 index 0000000..6f9250a --- /dev/null +++ b/src/core/common/Location.cpp @@ -0,0 +1,23 @@ +/* +    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 <http://www.gnu.org/licenses/>. +*/ + +#include "Location.hpp" + +namespace ousia { +} + diff --git a/src/core/common/Location.hpp b/src/core/common/Location.hpp index 39e1011..4ce01a8 100644 --- a/src/core/common/Location.hpp +++ b/src/core/common/Location.hpp @@ -16,91 +16,334 @@      along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ +/** + * @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 <cstdint> +#include <limits>  #include <string>  namespace ousia {  /** - * Struct representing a location within a source file. A position is defined by - * a byte offset (which is always reproducable), a line number and a column - * number (which may differ depending on the encoding used). + * Type used for referencing a source file currently opened in a Project. + */ +using SourceId = uint32_t; + +/** + * Maximum value for a SourceId. Indicates invalid entries. + */ +constexpr SourceId InvalidSourceId = std::numeric_limits<SourceId>::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<SourceOffset>::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.   */ -struct SourceLocation { +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:  	/** -	 * Current line, starting with one. +	 * Default constructor of the SourcePosition class. Sets the position to +	 * InvalidSourceOffset and thus marks the SourcePosition as invalid.  	 */ -	int line; +	SourcePosition() : pos(InvalidSourceOffset) {}  	/** -	 * Current column, starting with one. +	 * Creates a new SourcePosition instance with the given byte offset.  	 */ -	int column; +	SourcePosition(size_t pos) : pos(clampToSourcePosition(pos)) {}  	/** -	 * Current byte offset. +	 * 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.  	 */ -	size_t offs; +	void setPosition(size_t pos) { this->pos = clampToSourcePosition(pos); }  	/** -	 * Default constructor of the SourceLocation struct, initializes all -	 * memebers with zero. +	 * Returns the position value. Only use the value if "valid" returns true. +	 * +	 * @return the current position.  	 */ -	SourceLocation() : line(0), column(0), offs(0) {} +	SourceOffset getPosition() const { return pos; }  	/** -	 * Creates a new SourceLocation struct with only a line and no column. +	 * Returns true if the source position is valid, false otherwise. Invalid +	 * positions are set to the maximum representable number.  	 * -	 * @param line is the line number. -	 * @param column is the column number. +	 * @return true if the SourcePosition instance is value, false otherwise. +	 */ +	bool isValid() { 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.  	 */ -	SourceLocation(int line) : line(line), column(0), offs(0) {} +	SourceRange(){};  	/** -	 * Creates a new SourceLocation struct with a line and column. +	 * Constructor for a zero-length range.  	 * -	 * @param line is the line number. -	 * @param column is the column number. +	 * @param pos is the byte offset at which the SourceRange instance should be +	 * located.  	 */ -	SourceLocation(int line, int column) : line(line), column(column), offs(0) +	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)  	{  	}  	/** -	 * Creates a new SourceLocation struct with a line, column and byte offset. +	 * 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 line is the line number. -	 * @param column is the column number. -	 * @param offs is the byte offset. +	 * @param pos is the end position that should be set.  	 */ -	SourceLocation(int line, int column, size_t offs) -	    : line(line), column(column), offs(offs) +	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;  	}  	/** -	 * Returns true, if the line number is valid, false otherwise. +	 * 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".  	 * -	 * @return true for valid line numbers. +	 * @param pos is the position to which start and end should be set.  	 */ -	bool hasLine() const { return line > 0; } +	void setPosition(SourcePosition pos) +	{ +		this->start = pos; +		this->end = pos; +	}  	/** -	 * Returns true, if the column number is valid, false otherwise. +	 * Returns the start position of the SourceRange instance.  	 * -	 * @return true for valid column numbers. +	 * @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.  	 */ -	bool hasColumn() const { return column > 0; } +	SourcePosition getStartPosition() const { return start; }  	/** -	 * Returns true, if the position is valid, false otherwise. This function is -	 * equivalent to the hasLine() function. +	 * Returns a copy of the underlying SourcePosition instance representing the +	 * end position.  	 * -	 * @return true if the Position struct is valid. +	 * @return a copy of the end SourcePosition instance.  	 */ -	bool valid() const { return hasLine(); } +	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() +	{ +		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() { 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() +	{ +		return SourceRange::isValid() && sourceId != InvalidSourceId; +	}  };  /** @@ -109,6 +352,37 @@ struct SourceLocation {   */  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. +	 */ +	int startLine; + +	/** +	 * Start column, starting with one. +	 */ +	int startColumn; + +	/** +	 * End line, starting with one. +	 */ +	int endLine; + +	/** +	 * End column, starting with one. +	 */ +	int endColumn; + +	/**  	 * Set to the content of the current line.  	 */  	std::string text; @@ -120,6 +394,12 @@ struct SourceContext {  	int relPos;  	/** +	 * Relative length (in characters) within that line. May end beyond the +	 * text given in the context. +	 */ +	int 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). @@ -134,39 +414,40 @@ struct SourceContext {  	bool truncatedEnd;  	/** -	 * Default constructor, initializes all members with zero values. +	 * Default constructor, initializes primitive members with zero values.  	 */  	SourceContext() -	    : text(), relPos(0), truncatedStart(false), truncatedEnd(false) +	    : startLine(0), +	      startColumn(0), +	      endLine(0), +	      endColumn(0), +	      relPos(0), +	      relLen(0), +	      truncatedStart(false), +	      truncatedEnd(false)  	{  	}  	/** -	 * Constructor of the SourceContext class. +	 * Returns true the context text is not empty.  	 * -	 * @param text is the current line the text cursor is at. -	 * @param relPos is the relative position of the text cursor within that -	 * line. -	 * @param truncatedStart specifies whether the text was truncated at the -	 * beginning. -	 * @param truncatedEnd specifies whether the text was truncated at the -	 * end. -	 */ -	SourceContext(std::string text, size_t relPos, bool truncatedStart, -	              bool truncatedEnd) -	    : text(std::move(text)), -	      relPos(relPos), -	      truncatedStart(truncatedStart), -	      truncatedEnd(truncatedEnd) -	{ -	} +	 * @return true if the context is valid and e.g. should be printed. +	 */ +	bool isValid() const { return range.isValid() && hasLine() && hasColumn(); }  	/** -	 * Returns true the context text is not empty. +	 * Returns true, if the start line number is valid, false otherwise.  	 * -	 * @return true if the context is valid and e.g. should be printed. +	 * @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 valid() const { return !text.empty(); } +	bool hasColumn() const { return startColumn > 0; }  };  /** diff --git a/src/core/common/Rtti.cpp b/src/core/common/Rtti.cpp index 1213669..668e418 100644 --- a/src/core/common/Rtti.cpp +++ b/src/core/common/Rtti.cpp @@ -125,6 +125,17 @@ bool Rtti::isa(const Rtti &other) const  	return parents.count(&other) > 0;  } +bool Rtii::isOneOf(const RttiSet &others) const +{ +	initialize(); +	for (const Rtti *other: others) { +		if (parents.count(other) > 0) { +			return true; +		} +	} +	return false; +} +  bool Rtti::composedOf(const Rtti &other) const  {  	initialize(); diff --git a/src/core/common/Rtti.hpp b/src/core/common/Rtti.hpp index fa2692f..53043e2 100644 --- a/src/core/common/Rtti.hpp +++ b/src/core/common/Rtti.hpp @@ -378,10 +378,21 @@ public:  	 *  	 * @param other is the other type for which the relation to this type  	 * should be checked. +	 * @return true if this type (directly or indirectly) has the given other +	 * type as parent or equals the other type.  	 */  	bool isa(const Rtti &other) const;  	/** +	 * Returns true if this Rtti instance is one of the given types. +	 * +	 * @param others is a set of other types to be checked. +	 * @return true if this type (directly or indirectly) has once of the given +	 * other types as parent or equals one of the other types. +	 */ +	bool isOneOf(const RttiSet &others) const; + +	/**  	 * Returns true if an instance of this type may have references to the other  	 * given type. This mechanism is used to prune impossible paths when  	 * resolving objects of a certain type by name in an object graph. diff --git a/src/core/common/Utils.cpp b/src/core/common/Utils.cpp index 5fde29c..c8fcdc6 100644 --- a/src/core/common/Utils.cpp +++ b/src/core/common/Utils.cpp @@ -17,7 +17,9 @@  */  #include <algorithm> +#include <cctype>  #include <limits> +#include <string>  #include "Utils.hpp" @@ -74,5 +76,26 @@ std::vector<std::string> Utils::split(const std::string &s, char delim)  	return res;  } +std::string Utils::toLower(std::string s) +{ +	std::transform(s.begin(), s.end(), s.begin(), tolower); +	return s; +} + +std::string Utils::extractFileExtension(const std::string &filename) +{ +	size_t n = 0; +	for (ssize_t i = filename.size() - 1; i >= 0; i--) { +		if (filename[i] == '/' || filename[i] == '\\') { +			return std::string{}; +		} +		if (filename[i] == '.') { +			return toLower(filename.substr(i + 1, n)); +		} +		n++; +	} +	return std::string{}; +} +  } diff --git a/src/core/common/Utils.hpp b/src/core/common/Utils.hpp index 1f7f142..22e0fd3 100644 --- a/src/core/common/Utils.hpp +++ b/src/core/common/Utils.hpp @@ -114,6 +114,26 @@ public:  	 * @return a vector of strings containing the splitted sub-strings.  	 */  	static std::vector<std::string> split(const std::string &s, char delim); + +	/** +	 * Converts the given string to lowercase (only works for ANSI characters). +	 * +	 * @param s is the string that should be converted to lowercase. +	 * @return s in lowercase. +	 */ +	static std::string toLower(std::string s); + +	/** +	 * Reads the file extension of the given filename. +	 * +	 * @param filename is the filename from which the extension should be +	 * extracted. +	 * @return the extension, excluding any leading dot. The extension is +	 * defined as the substring after the last dot in the given string, if the +	 * dot is after a slash or backslash. The extension is converted to +	 * lowercase. +	 */ +	static std::string extractFileExtension(const std::string &filename);  };  }  | 
