2018-05-01 21:50:34 +02:00
|
|
|
// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2018-02-16 20:42:17 +01:00
|
|
|
#ifndef FORTRAN_PARSER_MESSAGE_H_
|
|
|
|
#define FORTRAN_PARSER_MESSAGE_H_
|
2018-01-30 20:53:49 +01:00
|
|
|
|
|
|
|
// Defines a representation for sequences of compiler messages.
|
|
|
|
// Supports nested contextualization.
|
|
|
|
|
2018-05-04 22:00:35 +02:00
|
|
|
#include "char-block.h"
|
2018-04-18 20:26:17 +02:00
|
|
|
#include "char-set.h"
|
2018-02-09 23:04:11 +01:00
|
|
|
#include "provenance.h"
|
2018-06-18 20:03:43 +02:00
|
|
|
#include "../common/idioms.h"
|
|
|
|
#include "../common/reference-counted.h"
|
2018-03-20 18:59:07 +01:00
|
|
|
#include <cstddef>
|
2018-04-18 20:26:17 +02:00
|
|
|
#include <cstring>
|
2018-01-30 20:53:49 +01:00
|
|
|
#include <forward_list>
|
|
|
|
#include <optional>
|
|
|
|
#include <ostream>
|
|
|
|
#include <string>
|
2018-04-17 20:16:05 +02:00
|
|
|
#include <utility>
|
2018-05-04 22:00:35 +02:00
|
|
|
#include <variant>
|
2018-01-30 20:53:49 +01:00
|
|
|
|
2018-05-02 22:48:12 +02:00
|
|
|
namespace Fortran::parser {
|
2018-01-30 20:53:49 +01:00
|
|
|
|
2018-04-03 00:51:04 +02:00
|
|
|
// Use "..."_err_en_US and "..."_en_US literals to define the static
|
|
|
|
// text and fatality of a message.
|
2018-02-20 18:57:30 +01:00
|
|
|
class MessageFixedText {
|
2018-02-17 00:47:30 +01:00
|
|
|
public:
|
2018-04-03 00:51:04 +02:00
|
|
|
constexpr MessageFixedText(
|
|
|
|
const char str[], std::size_t n, bool isFatal = false)
|
2018-05-04 22:00:35 +02:00
|
|
|
: text_{str, n}, isFatal_{isFatal} {}
|
2018-02-20 18:57:30 +01:00
|
|
|
constexpr MessageFixedText(const MessageFixedText &) = default;
|
2018-05-04 22:59:56 +02:00
|
|
|
constexpr MessageFixedText(MessageFixedText &&) = default;
|
2018-02-20 18:57:30 +01:00
|
|
|
constexpr MessageFixedText &operator=(const MessageFixedText &) = default;
|
2018-05-04 22:59:56 +02:00
|
|
|
constexpr MessageFixedText &operator=(MessageFixedText &&) = default;
|
2018-02-17 00:47:30 +01:00
|
|
|
|
2018-05-04 22:00:35 +02:00
|
|
|
const CharBlock &text() const { return text_; }
|
2018-04-03 00:51:04 +02:00
|
|
|
bool isFatal() const { return isFatal_; }
|
2018-02-17 00:47:30 +01:00
|
|
|
|
|
|
|
private:
|
2018-05-04 22:00:35 +02:00
|
|
|
CharBlock text_;
|
2018-04-03 00:51:04 +02:00
|
|
|
bool isFatal_{false};
|
2018-02-17 00:47:30 +01:00
|
|
|
};
|
|
|
|
|
2018-04-03 19:29:04 +02:00
|
|
|
inline namespace literals {
|
2018-03-20 18:59:07 +01:00
|
|
|
constexpr MessageFixedText operator""_en_US(const char str[], std::size_t n) {
|
2018-04-03 00:51:04 +02:00
|
|
|
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 */};
|
2018-02-17 00:47:30 +01:00
|
|
|
}
|
2018-04-03 19:29:04 +02:00
|
|
|
} // namespace literals
|
2018-02-17 00:47:30 +01:00
|
|
|
|
2018-02-21 21:12:52 +01:00
|
|
|
class MessageFormattedText {
|
|
|
|
public:
|
|
|
|
MessageFormattedText(MessageFixedText, ...);
|
2018-05-04 22:59:56 +02:00
|
|
|
MessageFormattedText(const MessageFormattedText &) = default;
|
|
|
|
MessageFormattedText(MessageFormattedText &&) = default;
|
|
|
|
MessageFormattedText &operator=(const MessageFormattedText &) = default;
|
|
|
|
MessageFormattedText &operator=(MessageFormattedText &&) = default;
|
|
|
|
const std::string &string() const { return string_; }
|
2018-04-03 00:51:04 +02:00
|
|
|
bool isFatal() const { return isFatal_; }
|
2018-05-04 22:59:56 +02:00
|
|
|
std::string MoveString() { return std::move(string_); }
|
2018-02-21 21:12:52 +01:00
|
|
|
|
|
|
|
private:
|
|
|
|
std::string string_;
|
2018-04-03 00:51:04 +02:00
|
|
|
bool isFatal_{false};
|
2018-02-21 21:12:52 +01:00
|
|
|
};
|
|
|
|
|
2018-04-03 00:51:04 +02:00
|
|
|
// Represents a formatted rendition of "expected '%s'"_err_en_US
|
2018-05-04 22:00:35 +02:00
|
|
|
// on a constant text or a set of characters.
|
2018-02-21 21:12:52 +01:00
|
|
|
class MessageExpectedText {
|
|
|
|
public:
|
2018-05-04 22:00:35 +02:00
|
|
|
MessageExpectedText(const char *s, std::size_t n)
|
|
|
|
: u_{CharBlock{s, n == std::string::npos ? std::strlen(s) : n}} {}
|
|
|
|
constexpr explicit MessageExpectedText(CharBlock cb) : u_{cb} {}
|
|
|
|
constexpr explicit MessageExpectedText(char ch) : u_{SetOfChars{ch}} {}
|
|
|
|
constexpr explicit MessageExpectedText(SetOfChars set) : u_{set} {}
|
|
|
|
MessageExpectedText(const MessageExpectedText &) = default;
|
2018-05-04 22:59:56 +02:00
|
|
|
MessageExpectedText(MessageExpectedText &&) = default;
|
|
|
|
MessageExpectedText &operator=(const MessageExpectedText &) = default;
|
|
|
|
MessageExpectedText &operator=(MessageExpectedText &&) = default;
|
2018-04-18 20:26:17 +02:00
|
|
|
|
2018-05-04 22:00:35 +02:00
|
|
|
std::string ToString() const;
|
|
|
|
void Incorporate(const MessageExpectedText &);
|
2018-02-21 21:12:52 +01:00
|
|
|
|
|
|
|
private:
|
2018-05-04 22:00:35 +02:00
|
|
|
std::variant<CharBlock, SetOfChars> u_;
|
2018-02-21 21:12:52 +01:00
|
|
|
};
|
|
|
|
|
2018-06-18 20:03:43 +02:00
|
|
|
class Message : public common::ReferenceCounted<Message> {
|
2018-02-05 21:54:36 +01:00
|
|
|
public:
|
2018-06-18 20:03:43 +02:00
|
|
|
using Reference = common::CountedReference<Message>;
|
2018-04-17 19:28:25 +02:00
|
|
|
|
2018-04-20 00:46:02 +02:00
|
|
|
Message(const Message &) = default;
|
2018-03-23 23:14:52 +01:00
|
|
|
Message(Message &&) = default;
|
2018-05-04 22:59:56 +02:00
|
|
|
Message &operator=(const Message &) = default;
|
|
|
|
Message &operator=(Message &&) = default;
|
2018-03-23 23:14:52 +01:00
|
|
|
|
2018-05-04 22:59:56 +02:00
|
|
|
Message(ProvenanceRange pr, const MessageFixedText &t)
|
|
|
|
: location_{pr}, text_{t} {}
|
2018-07-19 18:53:42 +02:00
|
|
|
Message(ProvenanceRange pr, const MessageFormattedText &s)
|
|
|
|
: location_{pr}, text_{std::move(s)} {}
|
2018-04-21 01:56:58 +02:00
|
|
|
Message(ProvenanceRange pr, MessageFormattedText &&s)
|
2018-05-04 22:59:56 +02:00
|
|
|
: location_{pr}, text_{std::move(s)} {}
|
|
|
|
Message(ProvenanceRange pr, const MessageExpectedText &t)
|
|
|
|
: location_{pr}, text_{t} {}
|
2018-04-18 20:26:17 +02:00
|
|
|
|
2018-05-04 22:59:56 +02:00
|
|
|
Message(CharBlock csr, const MessageFixedText &t)
|
|
|
|
: location_{csr}, text_{t} {}
|
2018-07-19 18:53:42 +02:00
|
|
|
Message(CharBlock csr, const MessageFormattedText &s)
|
|
|
|
: location_{csr}, text_{std::move(s)} {}
|
2018-04-21 01:56:58 +02:00
|
|
|
Message(CharBlock csr, MessageFormattedText &&s)
|
2018-05-04 22:59:56 +02:00
|
|
|
: location_{csr}, text_{std::move(s)} {}
|
|
|
|
Message(CharBlock csr, const MessageExpectedText &t)
|
|
|
|
: location_{csr}, text_{t} {}
|
2018-02-09 23:04:11 +01:00
|
|
|
|
2018-05-05 00:03:10 +02:00
|
|
|
bool attachmentIsContext() const { return attachmentIsContext_; }
|
2018-05-04 23:39:29 +02:00
|
|
|
Reference attachment() const { return attachment_; }
|
2018-01-30 20:53:49 +01:00
|
|
|
|
2018-05-05 00:03:10 +02:00
|
|
|
void SetContext(Message *c) {
|
|
|
|
attachment_ = c;
|
|
|
|
attachmentIsContext_ = true;
|
|
|
|
}
|
|
|
|
void Attach(Message *);
|
2018-05-05 00:40:40 +02:00
|
|
|
template<typename... A> void Attach(A &&... args) {
|
|
|
|
Attach(new Message{std::forward<A>(args)...}); // reference-counted
|
|
|
|
}
|
2018-05-05 00:03:10 +02:00
|
|
|
|
2018-05-05 00:40:40 +02:00
|
|
|
bool SortBefore(const Message &that) const;
|
2018-05-04 22:59:56 +02:00
|
|
|
bool IsFatal() const;
|
2018-04-18 20:26:17 +02:00
|
|
|
std::string ToString() const;
|
2018-07-27 20:44:31 +02:00
|
|
|
std::optional<ProvenanceRange> GetProvenanceRange(const CookedSource &) const;
|
2018-05-02 19:02:00 +02:00
|
|
|
void Emit(
|
2018-03-23 23:14:52 +01:00
|
|
|
std::ostream &, const CookedSource &, bool echoSourceLine = true) const;
|
2018-05-04 23:39:29 +02:00
|
|
|
|
2018-07-28 02:06:55 +02:00
|
|
|
// If this Message or any of its attachments locates itself via a CharBlock
|
|
|
|
// within a particular CookedSource, replace its location with the
|
|
|
|
// corresponding ProvenanceRange.
|
|
|
|
void ResolveProvenances(const CookedSource &);
|
|
|
|
|
2018-05-04 22:59:56 +02:00
|
|
|
void Incorporate(Message &);
|
2018-01-30 20:53:49 +01:00
|
|
|
|
2018-02-05 21:54:36 +01:00
|
|
|
private:
|
2018-05-04 22:00:35 +02:00
|
|
|
bool AtSameLocation(const Message &) const;
|
|
|
|
|
|
|
|
std::variant<ProvenanceRange, CharBlock> location_;
|
2018-05-04 22:59:56 +02:00
|
|
|
std::variant<MessageFixedText, MessageFormattedText, MessageExpectedText>
|
|
|
|
text_;
|
2018-05-05 00:03:10 +02:00
|
|
|
bool attachmentIsContext_{false};
|
2018-05-04 23:39:29 +02:00
|
|
|
Reference attachment_;
|
2018-01-30 20:53:49 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
class Messages {
|
2018-02-05 21:54:36 +01:00
|
|
|
public:
|
2018-04-20 00:46:02 +02:00
|
|
|
Messages() {}
|
|
|
|
Messages(Messages &&that) : messages_{std::move(that.messages_)} {
|
2018-04-17 23:45:12 +02:00
|
|
|
if (!messages_.empty()) {
|
|
|
|
last_ = that.last_;
|
|
|
|
that.last_ = that.messages_.before_begin();
|
|
|
|
}
|
|
|
|
}
|
2018-01-30 20:53:49 +01:00
|
|
|
Messages &operator=(Messages &&that) {
|
2018-04-17 23:45:12 +02:00
|
|
|
messages_ = std::move(that.messages_);
|
|
|
|
if (messages_.empty()) {
|
|
|
|
last_ = messages_.before_begin();
|
|
|
|
} else {
|
|
|
|
last_ = that.last_;
|
|
|
|
that.last_ = that.messages_.before_begin();
|
|
|
|
}
|
2018-01-30 20:53:49 +01:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2018-03-30 01:06:31 +02:00
|
|
|
bool empty() const { return messages_.empty(); }
|
2018-04-20 02:02:12 +02:00
|
|
|
|
2018-05-05 00:40:40 +02:00
|
|
|
Message &Put(Message &&m) {
|
2018-04-17 20:16:05 +02:00
|
|
|
last_ = messages_.emplace_after(last_, std::move(m));
|
2018-05-05 00:40:40 +02:00
|
|
|
return *last_;
|
2018-04-17 20:16:05 +02:00
|
|
|
}
|
|
|
|
|
2018-04-18 20:26:17 +02:00
|
|
|
template<typename... A> Message &Say(A &&... args) {
|
2018-04-17 20:16:05 +02:00
|
|
|
last_ = messages_.emplace_after(last_, std::forward<A>(args)...);
|
2018-04-18 20:26:17 +02:00
|
|
|
return *last_;
|
2018-01-30 20:53:49 +01:00
|
|
|
}
|
|
|
|
|
2018-04-14 01:00:03 +02:00
|
|
|
void Annex(Messages &that) {
|
|
|
|
if (!that.messages_.empty()) {
|
2018-04-17 20:16:05 +02:00
|
|
|
messages_.splice_after(last_, that.messages_);
|
2018-04-14 01:00:03 +02:00
|
|
|
last_ = that.last_;
|
2018-04-17 23:45:12 +02:00
|
|
|
that.last_ = that.messages_.before_begin();
|
2018-01-30 20:53:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-24 22:51:27 +02:00
|
|
|
void Restore(Messages &&that) {
|
|
|
|
that.Annex(*this);
|
|
|
|
*this = std::move(that);
|
|
|
|
}
|
|
|
|
|
2018-04-18 22:24:41 +02:00
|
|
|
void Incorporate(Messages &);
|
2018-04-20 00:46:02 +02:00
|
|
|
void Copy(const Messages &);
|
2018-07-27 23:01:19 +02:00
|
|
|
void ResolveProvenances(const CookedSource &);
|
2018-04-20 00:46:02 +02:00
|
|
|
void Emit(std::ostream &, const CookedSource &cooked,
|
2018-05-02 21:07:49 +02:00
|
|
|
bool echoSourceLines = true) const;
|
2018-02-09 23:04:11 +01:00
|
|
|
|
2018-04-03 00:51:04 +02:00
|
|
|
bool AnyFatalError() const;
|
|
|
|
|
2018-02-05 21:54:36 +01:00
|
|
|
private:
|
2018-07-12 23:46:23 +02:00
|
|
|
std::forward_list<Message> messages_;
|
|
|
|
std::forward_list<Message>::iterator last_{messages_.before_begin()};
|
2018-01-30 20:53:49 +01:00
|
|
|
};
|
2018-05-02 22:48:12 +02:00
|
|
|
|
2018-07-24 21:58:29 +02:00
|
|
|
class ContextualMessages {
|
|
|
|
public:
|
|
|
|
ContextualMessages(CharBlock at, Messages *m) : at_{at}, messages_{m} {}
|
|
|
|
template<typename... A> void Say(A &&... args) {
|
|
|
|
if (messages_ != nullptr) {
|
|
|
|
messages_->Say(at_, std::forward<A>(args)...);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
CharBlock at_;
|
|
|
|
Messages *messages_{nullptr};
|
|
|
|
};
|
2018-05-02 22:48:12 +02:00
|
|
|
} // namespace Fortran::parser
|
2018-02-16 20:42:17 +01:00
|
|
|
#endif // FORTRAN_PARSER_MESSAGE_H_
|