llvm/flang/lib/parser/message.h
2018-04-23 15:44:28 -07:00

215 lines
6.3 KiB
C++

#ifndef FORTRAN_PARSER_MESSAGE_H_
#define FORTRAN_PARSER_MESSAGE_H_
// Defines a representation for sequences of compiler messages.
// Supports nested contextualization.
#include "char-set.h"
#include "idioms.h"
#include "provenance.h"
#include "reference-counted.h"
#include <cstddef>
#include <cstring>
#include <forward_list>
#include <optional>
#include <ostream>
#include <string>
#include <utility>
namespace Fortran {
namespace parser {
// Use "..."_err_en_US and "..."_en_US literals to define the static
// text and fatality of a message.
class MessageFixedText {
public:
MessageFixedText() {}
constexpr MessageFixedText(
const char str[], std::size_t n, bool isFatal = false)
: str_{str}, bytes_{n}, isFatal_{isFatal} {}
constexpr MessageFixedText(const MessageFixedText &) = default;
MessageFixedText(MessageFixedText &&) = default;
constexpr MessageFixedText &operator=(const MessageFixedText &) = default;
MessageFixedText &operator=(MessageFixedText &&) = default;
const char *str() const { return str_; }
std::size_t size() const { return bytes_; }
bool empty() const { return bytes_ == 0; }
bool isFatal() const { return isFatal_; }
std::string ToString() const;
private:
const char *str_{nullptr};
std::size_t bytes_{0};
bool isFatal_{false};
};
inline namespace literals {
constexpr MessageFixedText operator""_en_US(const char str[], std::size_t n) {
return MessageFixedText{str, n, false /* not fatal */};
}
constexpr MessageFixedText operator""_err_en_US(
const char str[], std::size_t n) {
return MessageFixedText{str, n, true /* fatal */};
}
} // namespace literals
class MessageFormattedText {
public:
MessageFormattedText(MessageFixedText, ...);
std::string MoveString() { return std::move(string_); }
bool isFatal() const { return isFatal_; }
private:
std::string string_;
bool isFatal_{false};
};
// Represents a formatted rendition of "expected '%s'"_err_en_US
// on a constant text.
class MessageExpectedText {
public:
MessageExpectedText(const char *s, std::size_t n) : str_{s}, bytes_{n} {
if (n == std::string::npos) {
bytes_ = std::strlen(s);
}
}
MessageExpectedText(MessageExpectedText &&) = default;
explicit MessageExpectedText(char ch) : set_{ch} {}
explicit MessageExpectedText(SetOfChars set) : set_{set} {}
const char *str() const { return str_; }
std::size_t size() const { return bytes_; }
SetOfChars set() const { return set_; }
private:
const char *str_{nullptr};
std::size_t bytes_{0};
SetOfChars set_;
};
class Message : public ReferenceCounted<Message> {
public:
using Context = CountedReference<Message>;
Message() {}
Message(const Message &) = default;
Message(Message &&) = default;
Message &operator=(const Message &that) = default;
Message &operator=(Message &&that) = default;
Message(ProvenanceRange pr, MessageFixedText t)
: provenanceRange_{pr}, fixedText_{t.str()},
fixedBytes_{t.size()}, isFatal_{t.isFatal()} {}
Message(ProvenanceRange pr, MessageFormattedText &&s)
: provenanceRange_{pr}, string_{s.MoveString()}, isFatal_{s.isFatal()} {}
Message(ProvenanceRange pr, MessageExpectedText t)
: provenanceRange_{pr}, fixedText_{t.str()}, fixedBytes_{t.size()},
isExpected_{true}, expected_{t.set()}, isFatal_{true} {}
Message(CharBlock csr, MessageFixedText t)
: cookedSourceRange_{csr}, fixedText_{t.str()},
fixedBytes_{t.size()}, isFatal_{t.isFatal()} {}
Message(CharBlock csr, MessageFormattedText &&s)
: cookedSourceRange_{csr}, string_{s.MoveString()}, isFatal_{s.isFatal()} {}
Message(CharBlock csr, MessageExpectedText t)
: cookedSourceRange_{csr}, fixedText_{t.str()}, fixedBytes_{t.size()},
isExpected_{true}, expected_{t.set()}, isFatal_{true} {}
bool operator<(const Message &that) const {
if (cookedSourceRange_.begin() != nullptr) {
return cookedSourceRange_.begin() < that.cookedSourceRange_.begin();
} else if (that.cookedSourceRange_.begin() != nullptr) {
return false;
} else {
return provenanceRange_.start() < that.provenanceRange_.start();
}
}
ProvenanceRange provenanceRange() const { return provenanceRange_; }
Provenance provenance() const { return provenanceRange_.start(); }
CharBlock cookedSourceRange() const { return cookedSourceRange_; }
const char *cookedSourceLocation() const {
return cookedSourceRange_.begin();
}
Context context() const { return context_; }
Message &set_context(Message *c) {
context_ = c;
return *this;
}
bool isFatal() const { return isFatal_; }
void Incorporate(Message &);
std::string ToString() const;
ProvenanceRange Emit(
std::ostream &, const CookedSource &, bool echoSourceLine = true) const;
private:
ProvenanceRange provenanceRange_;
CharBlock cookedSourceRange_;
const char *fixedText_{nullptr};
std::size_t fixedBytes_{0};
bool isExpected_{false};
std::string string_;
SetOfChars expected_;
Context context_;
bool isFatal_{false};
};
class Messages {
public:
Messages() {}
Messages(Messages &&that) : messages_{std::move(that.messages_)} {
if (!messages_.empty()) {
last_ = that.last_;
that.last_ = that.messages_.before_begin();
}
}
Messages &operator=(Messages &&that) {
messages_ = std::move(that.messages_);
if (messages_.empty()) {
last_ = messages_.before_begin();
} else {
last_ = that.last_;
that.last_ = that.messages_.before_begin();
}
return *this;
}
bool empty() const { return messages_.empty(); }
void Put(Message &&m) {
last_ = messages_.emplace_after(last_, std::move(m));
}
template<typename... A> Message &Say(A &&... args) {
last_ = messages_.emplace_after(last_, std::forward<A>(args)...);
return *last_;
}
void Annex(Messages &that) {
if (!that.messages_.empty()) {
messages_.splice_after(last_, that.messages_);
last_ = that.last_;
that.last_ = that.messages_.before_begin();
}
}
void Incorporate(Messages &);
void Copy(const Messages &);
void Emit(std::ostream &, const CookedSource &cooked,
const char *prefix = nullptr, bool echoSourceLines = true) const;
bool AnyFatalError() const;
private:
using listType = std::forward_list<Message>;
listType messages_;
listType::iterator last_{messages_.before_begin()};
};
} // namespace parser
} // namespace Fortran
#endif // FORTRAN_PARSER_MESSAGE_H_