mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
471 lines
13 KiB
C++
471 lines
13 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/OwnedString.h"
|
|
#include "swift/Basic/JSONSerialization.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
|
|
};
|
|
|
|
/// 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
|
|
|
|
/// 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
|
|
}
|
|
}
|
|
|
|
bool isComment() const;
|
|
|
|
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.
|
|
void dump() const;
|
|
|
|
/// 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 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 ScalarEnumerationTraits<syntax::TriviaKind> {
|
|
static void enumeration(Output &out, syntax::TriviaKind &value) {
|
|
% for trivia in TRIVIAS:
|
|
out.enumCase(value, "${trivia.name}", syntax::TriviaKind::${trivia.name});
|
|
% end
|
|
}
|
|
};
|
|
} // 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, text);
|
|
% end
|
|
break;
|
|
}
|
|
% end
|
|
}
|
|
}
|
|
};
|
|
|
|
/// 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
|