mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
371 lines
11 KiB
C++
371 lines
11 KiB
C++
//===--- Trivia.h - Swift Syntax Trivia Interface ---------------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 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 "llvm/Support/raw_ostream.h"
|
|
|
|
#include <deque>
|
|
|
|
namespace swift {
|
|
namespace syntax {
|
|
|
|
class AbsolutePosition;
|
|
|
|
/// The kind of source trivia, such as spaces, newlines, or comments.
|
|
enum class TriviaKind {
|
|
/// A space ' ' character.
|
|
Space,
|
|
|
|
/// A tab '\t' character.
|
|
Tab,
|
|
|
|
/// A vertical tab '\v' character.
|
|
VerticalTab,
|
|
|
|
/// A form-feed '\f' character.
|
|
Formfeed,
|
|
|
|
/// A newline '\n' character.
|
|
Newline,
|
|
|
|
/// A developer line comment, starting with '//'
|
|
LineComment,
|
|
|
|
/// A developer block comment, starting with '/*' and ending with '*/'.
|
|
BlockComment,
|
|
|
|
/// A documentation line comment, starting with '///'.
|
|
DocLineComment,
|
|
|
|
/// A documentation block comment, starting with '/**' and ending with '*/.
|
|
DocBlockComment,
|
|
|
|
/// A backtick '`' character, used to escape identifiers.
|
|
Backtick,
|
|
};
|
|
|
|
/// 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.
|
|
struct TriviaPiece {
|
|
TriviaKind Kind;
|
|
unsigned Count;
|
|
OwnedString Text;
|
|
|
|
TriviaPiece(const TriviaKind Kind, const unsigned Count,
|
|
const OwnedString Text)
|
|
: Kind(Kind), Count(Count), Text(Text) {}
|
|
|
|
/// Return a piece of trivia for some number of space characters in a row.
|
|
static TriviaPiece spaces(unsigned Count) {
|
|
return TriviaPiece {TriviaKind::Space, Count, OwnedString{}};
|
|
}
|
|
|
|
/// Return a piece of trivia for some number of tab characters in a row.
|
|
static TriviaPiece tabs(unsigned Count) {
|
|
return TriviaPiece {TriviaKind::Tab, Count, OwnedString{}};
|
|
}
|
|
|
|
/// Return a piece of trivia for some number of newline characters
|
|
/// in a row.
|
|
static TriviaPiece newlines(unsigned Count) {
|
|
return TriviaPiece {TriviaKind::Newline, Count, OwnedString{}};
|
|
}
|
|
|
|
/// Return a piece of trivia for a single line of ('//') developer comment.
|
|
static TriviaPiece lineComment(const OwnedString Text) {
|
|
return TriviaPiece {TriviaKind::LineComment, 1, Text};
|
|
}
|
|
|
|
/// Return a piece of trivia for a block comment ('/* ... */')
|
|
static TriviaPiece blockComment(const OwnedString Text) {
|
|
return TriviaPiece {TriviaKind::BlockComment, 1, Text};
|
|
}
|
|
|
|
/// Return a piece of trivia for a single line of ('///') doc comment.
|
|
static TriviaPiece docLineComment(const OwnedString Text) {
|
|
return TriviaPiece {TriviaKind::DocLineComment, 1, Text};
|
|
}
|
|
|
|
/// Return a piece of trivia for a documentation block comment ('/** ... */')
|
|
static TriviaPiece docBlockComment(const OwnedString Text) {
|
|
return TriviaPiece {TriviaKind::DocBlockComment, 1, Text};
|
|
}
|
|
|
|
/// Return a piece of trivia for a single backtick '`' for escaping
|
|
/// an identifier.
|
|
static TriviaPiece backtick() {
|
|
return TriviaPiece {TriviaKind::Backtick, 1, OwnedString{}};
|
|
}
|
|
|
|
void accumulateAbsolutePosition(AbsolutePosition &Pos) const;
|
|
|
|
/// 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);
|
|
}
|
|
};
|
|
|
|
using TriviaList = std::deque<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.push_front(Piece);
|
|
}
|
|
|
|
/// 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();
|
|
}
|
|
|
|
/// 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);
|
|
}
|
|
|
|
/// Return a collection of trivia of some number of space characters in a row.
|
|
static Trivia spaces(unsigned Count) {
|
|
if (Count == 0) {
|
|
return {};
|
|
}
|
|
return {{ TriviaPiece {TriviaKind::Space, Count, OwnedString{}} }};
|
|
}
|
|
|
|
/// Return a collection of trivia of some number of tab characters in a row.
|
|
static Trivia tabs(unsigned Count) {
|
|
if (Count == 0) {
|
|
return {};
|
|
}
|
|
return {{ TriviaPiece {TriviaKind::Tab, Count, OwnedString{}} }};
|
|
}
|
|
|
|
/// Return a collection of trivia of some number of newline characters
|
|
// in a row.
|
|
static Trivia newlines(unsigned Count) {
|
|
if (Count == 0) {
|
|
return {};
|
|
}
|
|
return {{ TriviaPiece {TriviaKind::Newline, Count, OwnedString{}} }};
|
|
}
|
|
|
|
/// Return a collection of trivia with a single line of ('//')
|
|
// developer comment.
|
|
static Trivia lineComment(const OwnedString Text) {
|
|
assert(Text.str().startswith("//"));
|
|
return {{ TriviaPiece {TriviaKind::LineComment, 1, Text} }};
|
|
}
|
|
|
|
/// Return a collection of trivia with a block comment ('/* ... */')
|
|
static Trivia blockComment(const OwnedString Text) {
|
|
assert(Text.str().startswith("/*"));
|
|
assert(Text.str().endswith("*/"));
|
|
return {{ TriviaPiece {TriviaKind::BlockComment, 1, Text} }};
|
|
}
|
|
|
|
/// Return a collection of trivia with a single line of ('///') doc comment.
|
|
static Trivia docLineComment(const OwnedString Text) {
|
|
assert(Text.str().startswith("///"));
|
|
return {{ TriviaPiece {TriviaKind::DocLineComment, 1, Text} }};
|
|
}
|
|
|
|
/// Return a collection of trivia with a documentation block
|
|
// comment ('/** ... */')
|
|
static Trivia docBlockComment(const OwnedString Text) {
|
|
assert(Text.str().startswith("/**"));
|
|
assert(Text.str().endswith("*/"));
|
|
return {{ TriviaPiece {TriviaKind::DocBlockComment, 1, Text} }};
|
|
}
|
|
|
|
/// Return a piece of trivia for a single backtick '`' for escaping
|
|
/// an identifier.
|
|
static Trivia backtick() {
|
|
return {{ TriviaPiece {TriviaKind::Backtick, 1, OwnedString{}} }};
|
|
}
|
|
};
|
|
}
|
|
}
|
|
#endif // SWIFT_SYNTAX_TRIVIA_H
|