mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
It does not yet understand a lot of ReST constructs, in particular, it does not understand inline markup at all, but it is good enough to extract brief comments. The parser in BriefParser.cpp does not construct any ASTs or emit any warnings. This is a special parser for brief comments that should be as fast as possible. Real ReST parser will come later. Swift SVN r15046
154 lines
4.7 KiB
C++
154 lines
4.7 KiB
C++
//===--- SourceLoc.h - ReST source location and source manager classes ----===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
#ifndef LLVM_REST_SOURCELOC_H
|
|
#define LLVM_REST_SOURCELOC_H
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
namespace llvm {
|
|
namespace rest {
|
|
|
|
class SourceLoc {
|
|
friend class SourceManagerBase;
|
|
|
|
template<typename ExternalSourceLocTy>
|
|
friend class SourceManager;
|
|
|
|
unsigned Value;
|
|
|
|
static const unsigned InvalidValue = 0;
|
|
|
|
public:
|
|
SourceLoc() : Value(InvalidValue) {}
|
|
SourceLoc(const SourceLoc &) = default;
|
|
|
|
bool isValid() const { return !isInvalid(); }
|
|
bool isInvalid() const { return Value == InvalidValue; }
|
|
|
|
bool operator==(SourceLoc RHS) const { return Value == RHS.Value; }
|
|
bool operator!=(SourceLoc RHS) const { return !(*this == RHS); }
|
|
|
|
/// Return a source location advanced a specified number of bytes.
|
|
SourceLoc getAdvancedLoc(int ByteOffset) const {
|
|
assert(isValid() && "Can't advance an invalid location");
|
|
SourceLoc Result = *this;
|
|
Result.Value += ByteOffset;
|
|
return Result;
|
|
}
|
|
};
|
|
|
|
class SourceRange {
|
|
public:
|
|
/// The source range is a half-open byte range [Start; End).
|
|
SourceLoc Start, End;
|
|
|
|
SourceRange() {}
|
|
SourceRange(SourceLoc Loc) : Start(Loc), End(Loc) { }
|
|
SourceRange(SourceLoc Start, SourceLoc End) : Start(Start), End(End) {
|
|
assert(Start.isValid() == End.isValid() &&
|
|
"Start and end should either both be valid or both be invalid!");
|
|
}
|
|
|
|
bool isValid() const { return Start.isValid(); }
|
|
bool isInvalid() const { return Start.isInvalid(); }
|
|
};
|
|
|
|
class SourceManagerBase {
|
|
protected:
|
|
SourceLoc NextUnassignedLoc;
|
|
|
|
/// All source pieces, in order of increasing source location.
|
|
std::vector<SourceRange> RegisteredRanges;
|
|
|
|
public:
|
|
SourceManagerBase() : NextUnassignedLoc() {
|
|
NextUnassignedLoc.Value = 1;
|
|
}
|
|
SourceManagerBase(const SourceManagerBase &) = delete;
|
|
|
|
void operator=(const SourceManagerBase &) = delete;
|
|
|
|
bool isBeforeInBuffer(SourceLoc LHS, SourceLoc RHS) const {
|
|
// When we support multiple buffers, assert that locations come from the
|
|
// same buffer.
|
|
return LHS.Value < RHS.Value;
|
|
}
|
|
|
|
/// Returns true if range \c R contains the location \c Loc.
|
|
bool containsLoc(SourceRange R, SourceLoc Loc) const {
|
|
return Loc == R.Start ||
|
|
(isBeforeInBuffer(R.Start, Loc) && isBeforeInBuffer(Loc, R.End));
|
|
}
|
|
};
|
|
|
|
template <typename ExternalSourceLocTy>
|
|
class SourceManager : public SourceManagerBase {
|
|
std::vector<ExternalSourceLocTy> ExternalLocs;
|
|
|
|
public:
|
|
SourceManager() = default;
|
|
SourceManager(const SourceManager &) = delete;
|
|
|
|
void operator=(const SourceManager &) = delete;
|
|
|
|
SourceRange registerLine(StringRef Line, ExternalSourceLocTy ExternalLoc);
|
|
|
|
/// Returns the external source range and a byte offset inside it.
|
|
std::pair<ExternalSourceLocTy, unsigned>
|
|
toExternalSourceLoc(SourceLoc Loc) const;
|
|
};
|
|
|
|
template <typename ExternalSourceLocTy>
|
|
SourceRange SourceManager<ExternalSourceLocTy>::registerLine(
|
|
StringRef Line, ExternalSourceLocTy ExternalLoc) {
|
|
if (Line.size() > 4095)
|
|
return SourceRange();
|
|
|
|
SourceLoc Start = NextUnassignedLoc;
|
|
SourceLoc End = Start.getAdvancedLoc(Line.size());
|
|
RegisteredRanges.push_back(SourceRange(Start, End));
|
|
ExternalLocs.push_back(ExternalLoc);
|
|
NextUnassignedLoc = End.getAdvancedLoc(2);
|
|
#ifndef NDEBUG
|
|
// To make debugging easier, make each line start at offset that is equal to
|
|
// 1 mod 1000.
|
|
NextUnassignedLoc.Value = ((NextUnassignedLoc.Value + 999) % 1000) * 1000 + 1;
|
|
#endif
|
|
return SourceRange(Start, End);
|
|
}
|
|
|
|
template <typename ExternalSourceLocTy>
|
|
std::pair<ExternalSourceLocTy, unsigned>
|
|
SourceManager<ExternalSourceLocTy>::toExternalSourceLoc(SourceLoc Loc) const {
|
|
auto I = std::lower_bound(RegisteredRanges.begin(), RegisteredRanges.end(),
|
|
Loc, [this](const SourceRange &LHS, SourceLoc Loc) {
|
|
return this->isBeforeInBuffer(LHS.Start, Loc);
|
|
});
|
|
assert(I != RegisteredRanges.end() && "unknown source location");
|
|
const auto &InternalRange = *I;
|
|
assert(containsLoc(InternalRange, Loc) && "unknown source location");
|
|
const auto &ExternalLoc = ExternalLocs[I - RegisteredRanges.begin()];
|
|
return { ExternalLoc, Loc.Value - InternalRange.Start.Value };
|
|
}
|
|
|
|
} // namespace rest
|
|
} // namespace llvm
|
|
|
|
#endif // LLVM_REST_SOURCELOC_H
|
|
|