Files
swift-mirror/include/swift/Syntax/Trivia.h.gyb
Brent Royal-Gordon 99faa033fc [NFC] Standardize dump() methods in frontend
By convention, most structs and classes in the Swift compiler include a `dump()` method which prints debugging information. This method is meant to be called only from the debugger, but this means they’re often unused and may be eliminated from optimized binaries. On the other hand, some parts of the compiler call `dump()` methods directly despite them being intended as a pure debugging aid. clang supports attributes which can be used to avoid these problems, but they’re used very inconsistently across the compiler.

This commit adds `SWIFT_DEBUG_DUMP` and `SWIFT_DEBUG_DUMPER(<name>(<params>))` macros to declare `dump()` methods with the appropriate set of attributes and adopts this macro throughout the frontend. It does not pervasively adopt this macro in SILGen, SILOptimizer, or IRGen; these components use `dump()` methods in a different way where they’re frequently called from debugging code. Nor does it adopt it in runtime components like swiftRuntime and swiftReflection, because I’m a bit worried about size.

Despite the large number of files and lines affected, this change is NFC.
2019-10-31 18:37:42 -07:00

538 lines
15 KiB
C++

%{
# -*- mode: C++ -*-
from gyb_syntax_support import *
from gyb_syntax_support.Trivia import TRIVIAS
# Ignore the following admonition; it applies to the resulting .h file only
}%
//// Automatically Generated From Trivia.h.gyb.
//// Do Not Edit Directly!
//===--- Trivia.h - Swift Syntax Trivia Interface ---------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines a data structure representing "trivia" in the Swift
// language, such as formatting text like whitespace, or other pieces of
// syntax that don't affect program behavior, like comments.
//
// All source trivia except for comments are kind of "run-length encoded".
// For example, a token might follow 2 newlines and 2 spaces, like so:
//
// func foo() {
// var x = 2
// }
//
// Here, the 'var' keyword would have the following "leading" trivia:
// [ Newlines(2), Spaces(2) ]
//
// and the following "trailing" trivia:
// [ Spaces(1) ]
//
// Every terminal token in the tree has "leading" and "trailing" trivia.
//
// There is one basic rule to follow when attaching trivia:
//
// 1. A token owns all of its trailing trivia up to, but not including,
// the next newline character.
//
// 2. Looking backward in the text, a token owns all of the leading trivia
// up to and including the first contiguous sequence of newlines characters.
//
// For this example again:
//
// func foo() {
// var x = 2
// }
//
// 'func'
// - Has no leading trivia.
// - Takes up the space after because of rule 1.
// - Leading: [] Trailing: [ Space(1) ]
//
// 'foo'
// - Has no leading trivia. 'func' ate it as its trailing trivia.
// - Has no trailing trivia, because it is butted up against the next '('.
// - Leading: [] Trailing: []
//
// '('
// - Has no leading or trailing trivia.
// - Leading: [] Trailing: []
//
// ')'
// - Has no leading trivia.
// - Takes up the space after because of rule 1.
// - Leading: [] Trailing: [ Space(1) ]
//
// '{'
// - Has no leading trivia. ')' ate it as its trailing trivia.
// - Has no trailing trivia. Because of Rule 1, it doesn't take the newline.
// - Leading: [] Trailing: []
//
// 'var'
// - Takes the newline and preceding two spaces because of Rule 2.
// - Takes the single space that follows because of Rule 1.
// - Leading: [ Newline(1), Space(2) ] Trailing: [ Space(1) ]
//
// ... and so on.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SYNTAX_TRIVIA_H
#define SWIFT_SYNTAX_TRIVIA_H
#include "swift/Basic/Debug.h"
#include "swift/Basic/OwnedString.h"
#include "swift/Basic/JSONSerialization.h"
#include "swift/Basic/ByteTreeSerialization.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/YAMLTraits.h"
#include <vector>
namespace swift {
namespace syntax {
class AbsolutePosition;
/// The kind of source trivia, such as spaces, newlines, or comments.
enum class TriviaKind {
% for trivia in TRIVIAS:
// ${trivia.comment}
${trivia.name},
% end
};
bool isCommentTriviaKind(TriviaKind kind);
/// A contiguous stretch of a single kind of trivia. The constituent part of
/// a `Trivia` collection.
///
/// For example, four spaces would be represented by
/// { TriviaKind::Space, 4, "" }.
///
/// All trivia except for comments don't need to store text, since they can be
/// reconstituted using their Kind and Count.
///
/// In general, you should deal with the actual Trivia collection instead
/// of individual pieces whenever possible.
class TriviaPiece {
TriviaKind Kind;
unsigned Count;
OwnedString Text;
TriviaPiece(const TriviaKind Kind, const OwnedString Text)
: Kind(Kind), Count(1), Text(Text) {}
TriviaPiece(const TriviaKind Kind, const unsigned Count)
: Kind(Kind), Count(Count), Text() {}
friend struct json::ObjectTraits<TriviaPiece>;
friend struct llvm::yaml::MappingTraits<TriviaPiece>;
public:
% for trivia in TRIVIAS:
% if trivia.is_collection():
static TriviaPiece ${trivia.lower_name}s(unsigned Count) {
return {TriviaKind::${trivia.name}, Count};
}
static TriviaPiece ${trivia.lower_name}() {
return ${trivia.lower_name}s(1);
}
% else:
static TriviaPiece ${trivia.lower_name}(const OwnedString Text) {
return {TriviaKind::${trivia.name}, Text};
}
% end
% end
static TriviaPiece fromText(TriviaKind kind, StringRef text);
/// Return kind of the trivia.
TriviaKind getKind() const { return Kind; }
/// Return the text of the trivia.
StringRef getText() const { return Text.str(); }
/// Return the text of the trivia.
unsigned getCount() const { return Count; }
/// Return textual length of the trivia.
size_t getTextLength() const {
switch (Kind) {
% for trivia in TRIVIAS:
case TriviaKind::${trivia.name}:
% if trivia.is_collection():
return Count * ${trivia.characters_len()};
% else:
return Text.size();
% end
% end
}
llvm_unreachable("unhandled kind");
}
bool isComment() const {
return isCommentTriviaKind(getKind());
}
void accumulateAbsolutePosition(AbsolutePosition &Pos) const;
/// Try to compose this and Next to one TriviaPiece.
/// It returns true if it is succeeded.
bool trySquash(const TriviaPiece &Next);
/// Print a debug representation of this trivia piece to the provided output
/// stream and indentation level.
void dump(llvm::raw_ostream &OS, unsigned Indent = 0) const;
/// Print this piece of trivia to the provided output stream.
void print(llvm::raw_ostream &OS) const;
bool operator==(const TriviaPiece &Other) const {
return Kind == Other.Kind &&
Count == Other.Count &&
Text.str().compare(Other.Text.str()) == 0;
}
bool operator!=(const TriviaPiece &Other) const {
return !(*this == Other);
}
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(unsigned(Kind));
switch (Kind) {
% for trivia in TRIVIAS:
case TriviaKind::${trivia.name}:
% if trivia.is_collection():
ID.AddInteger(Count);
% else:
ID.AddString(Text.str());
% end
break;
% end
}
}
};
using TriviaList = std::vector<TriviaPiece>;
/// A collection of leading or trailing trivia. This is the main data structure
/// for thinking about trivia.
struct Trivia {
TriviaList Pieces;
/// Get the begin iterator of the pieces.
TriviaList::const_iterator begin() const {
return Pieces.begin();
}
/// Get the end iterator of the pieces.
TriviaList::const_iterator end() const {
return Pieces.end();
}
/// Add a piece to the end of the collection.
void push_back(const TriviaPiece &Piece) {
Pieces.push_back(Piece);
}
/// Add a piece to the beginning of the collection.
void push_front(const TriviaPiece &Piece) {
Pieces.insert(Pieces.begin(), Piece);
}
/// Clear pieces.
void clear() {
Pieces.clear();
}
/// Return a reference to the first piece.
///
/// Precondition: !empty()
const TriviaPiece &front() const {
assert(!empty());
return Pieces.front();
}
/// Return a reference to the last piece.
///
/// Precondition: !empty()
const TriviaPiece &back() const {
assert(!empty());
return Pieces.back();
}
/// Remove the last piece from the Trivia collection.
///
/// Precondition: !empty()
void pop_back() {
assert(!empty());
Pieces.pop_back();
}
/// Returns true if there are no pieces in this Trivia collection.
bool empty() const {
return Pieces.empty();
}
/// Return the number of pieces in this Trivia collection.
size_t size() const {
return Pieces.size();
}
size_t getTextLength() const {
size_t Len = 0;
for (auto &P : Pieces)
Len += P.getTextLength();
return Len;
}
/// Append Next TriviaPiece or compose last TriviaPiece and
/// Next TriviaPiece to one last TriviaPiece if it can.
void appendOrSquash(const TriviaPiece &Next);
/// Dump a debug representation of this Trivia collection to standard error.
SWIFT_DEBUG_DUMP;
/// Dump a debug representation of this Trivia collection to the provided
/// stream and indentation level.
void dump(llvm::raw_ostream &OS, unsigned Indent = 0) const;
/// Print all of the pieces to the provided output stream in source order.
void print(llvm::raw_ostream &OS) const;
/// Return a new Trivia collection by appending pieces from `Other`.
Trivia appending(const Trivia &Other) const;
Trivia operator+(const Trivia &Other) const;
/// Look for the first TriviaPiece with the DesiredKind. If not found,
/// returns the end iterator.
TriviaList::const_iterator find(const TriviaKind DesiredKind) const;
/// Returns true if the Trivia collection contains a piece of the given Kind.
bool contains(const TriviaKind Kind) const {
return find(Kind) != end();
}
bool operator==(const Trivia &Other) const {
if (Pieces.size() != Other.size()) {
return false;
}
for (size_t i = 0; i < Pieces.size(); ++i) {
if (Pieces[i] != Other.Pieces[i]) {
return false;
}
}
return true;
}
bool operator!=(const Trivia &Other) const {
return !(*this == Other);
}
% for trivia in TRIVIAS:
% if trivia.is_collection():
static Trivia ${trivia.lower_name}s(unsigned Count) {
if (Count == 0) {
return {};
}
return {{TriviaPiece::${trivia.lower_name}s(Count)}};
}
static Trivia ${trivia.lower_name}() {
return {{TriviaPiece::${trivia.lower_name}s(1)}};
}
% else:
static Trivia ${trivia.lower_name}(const OwnedString Text) {
assert(checkTriviaText(Text.str(), TriviaKind::${trivia.name}));
return {{TriviaPiece::${trivia.lower_name}(Text)}};
}
% end
% end
private:
static bool checkTriviaText(StringRef Text, TriviaKind Kind) {
switch(Kind) {
case TriviaKind::LineComment:
return Text.startswith("//");
case TriviaKind::BlockComment:
return Text.startswith("/*") && Text.endswith("*/");
case TriviaKind::DocLineComment:
return Text.startswith("///");
case TriviaKind::DocBlockComment:
return Text.startswith("/**") && Text.endswith("*/");
case TriviaKind::GarbageText:
return !Text.empty();
% for trivia in TRIVIAS:
% if trivia.is_collection():
case TriviaKind::${trivia.name}: return true;
% end
% end
}
}
};
} // namespace syntax
namespace byteTree {
template <>
struct WrapperTypeTraits<syntax::TriviaKind> {
static uint8_t numericValue(const syntax::TriviaKind &Kind) {
switch (Kind) {
% for trivia in TRIVIAS:
case syntax::TriviaKind::${trivia.name}: return ${trivia.serialization_code};
% end
}
llvm_unreachable("unhandled kind");
}
static void write(ByteTreeWriter &Writer, const syntax::TriviaKind &Kind,
unsigned Index) {
Writer.write(numericValue(Kind), Index);
}
};
template <>
struct ObjectTraits<syntax::TriviaPiece> {
static unsigned numFields(const syntax::TriviaPiece &Trivia,
UserInfoMap &UserInfo) {
return 2;
}
static void write(ByteTreeWriter &Writer, const syntax::TriviaPiece &Trivia,
UserInfoMap &UserInfo) {
Writer.write(Trivia.getKind(), /*Index=*/0);
// Write the trivia's text or count depending on its kind
switch (Trivia.getKind()) {
% for trivia in TRIVIAS:
case syntax::TriviaKind::${trivia.name}:
% if trivia.is_collection():
Writer.write(static_cast<uint32_t>(Trivia.getCount()), /*Index=*/1);
% else:
Writer.write(Trivia.getText(), /*Index=*/1);
% end
break;
% end
}
}
};
} // end namespace byteTree
namespace json {
/// Serialization traits for TriviaPiece.
/// - All trivia pieces will have a "kind" key that contains the serialized
/// name of the trivia kind.
/// - Comment trivia will have the associated text of the comment under the
/// "value" key.
/// - All other trivia will have the associated integer count of their
/// occurrences under the "value" key.
template<>
struct ObjectTraits<syntax::TriviaPiece> {
static void mapping(Output &out, syntax::TriviaPiece &value) {
auto kind = value.getKind();
out.mapRequired("kind", kind);
switch (kind) {
% for trivia in TRIVIAS:
case syntax::TriviaKind::${trivia.name}: {
% if trivia.is_collection():
auto count = value.getCount();
out.mapRequired("value", count);
% else:
auto text = value.getText();
out.mapRequired("value", text);
% end
break;
}
% end
}
}
};
/// Serialization traits for TriviaKind.
template <>
struct ScalarReferenceTraits<syntax::TriviaKind> {
static StringRef stringRef(const syntax::TriviaKind &value) {
switch (value) {
% for trivia in TRIVIAS:
case syntax::TriviaKind::${trivia.name}:
return "\"${trivia.name}\"";
% end
}
llvm_unreachable("unhandled kind");
}
static bool mustQuote(StringRef) {
// The string is already quoted. This is more efficient since it does not
// check for characters that need to be escaped
return false;
}
};
} // namespace json
} // namespace swift
namespace llvm {
namespace yaml {
/// Deserialization traits for TriviaPiece.
/// - All trivia pieces will have a "kind" key that contains the serialized
/// name of the trivia kind.
/// - Comment trivia will have the associated text of the comment under the
/// "value" key.
/// - All other trivia will have the associated integer count of their
/// occurrences under the "value" key.
template<>
struct MappingTraits<swift::syntax::TriviaPiece> {
static swift::syntax::TriviaPiece mapping(IO &in) {
swift::syntax::TriviaKind kind;
in.mapRequired("kind", kind);
switch (kind) {
% for trivia in TRIVIAS:
case swift::syntax::TriviaKind::${trivia.name}: {
% if trivia.is_collection():
/// FIXME: This is a workaround for existing bug from llvm yaml parser
/// which would raise error when deserializing number with trailing character
/// like "1\n". See https://bugs.llvm.org/show_bug.cgi?id=15505
StringRef str;
in.mapRequired("value", str);
unsigned count = std::atoi(str.data());
return swift::syntax::TriviaPiece(kind, count);
% else:
StringRef text;
in.mapRequired("value", text);
return swift::syntax::TriviaPiece(
kind, swift::OwnedString::makeRefCounted(text));
% end
break;
}
% end
}
llvm_unreachable("covered switch");
}
};
/// Deserialization traits for TriviaKind.
template <>
struct ScalarEnumerationTraits<swift::syntax::TriviaKind> {
static void enumeration(IO &in, swift::syntax::TriviaKind &value) {
% for trivia in TRIVIAS:
in.enumCase(value, "${trivia.name}", swift::syntax::TriviaKind::${trivia.name});
% end
}
};
} // namespace yaml
} // namespace llvm
#endif // SWIFT_SYNTAX_TRIVIA_H