mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
RawTokenSyntax is a derived class from RawSyntax that is reference counted with its own destructor function registered. Unfortunately, the destructor function of RawSyntax is non-virtual before this patch. This means when reference counter releases a pointer of RawSyntax, it won't clean-up the additional stuff in RawTokenSyntax.
308 lines
11 KiB
C++
308 lines
11 KiB
C++
//===--- RawSyntax.h - Swift Raw Syntax 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 the RawSyntax type.
|
|
//
|
|
// These are the "backbone or "skeleton" of the Syntax tree, providing
|
|
// the recursive structure, child relationships, kind of node, etc.
|
|
//
|
|
// They are reference-counted and strictly immutable, so can be shared freely
|
|
// among Syntax nodes and have no specific identity. They could even in theory
|
|
// be shared for expressions like 1 + 1 + 1 + 1 - you don't need 7 syntax nodes
|
|
// to express that at this layer.
|
|
//
|
|
// These are internal implementation ONLY - do not expose anything involving
|
|
// RawSyntax publicly. Clients of lib/Syntax should not be aware that they
|
|
// exist.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_SYNTAX_RAWSYNTAX_H
|
|
#define SWIFT_SYNTAX_RAWSYNTAX_H
|
|
|
|
#include "swift/Syntax/References.h"
|
|
#include "swift/Syntax/SyntaxKind.h"
|
|
#include "swift/Syntax/Trivia.h"
|
|
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
|
#include "llvm/ADT/PointerUnion.h"
|
|
#include "llvm/Support/Casting.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include <vector>
|
|
|
|
using llvm::cast;
|
|
using llvm::StringRef;
|
|
|
|
#ifndef NDEBUG
|
|
#define syntax_assert_child_kind(Raw, Cursor, ExpectedKind) \
|
|
(assert(Raw->getChild(Cursor)->Kind == ExpectedKind));
|
|
#else
|
|
#define syntax_assert_child_kind(Raw, Cursor, ExpectedKind) ({});
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
#define syntax_assert_child_token(Raw, CursorName, ...) \
|
|
({ \
|
|
bool __Found = false; \
|
|
auto __Token = cast<RawTokenSyntax>(Raw->getChild(Cursor::CursorName)); \
|
|
if (__Token->isPresent()) { \
|
|
for (auto Token : {__VA_ARGS__}) { \
|
|
if (__Token->getTokenKind() == Token) { \
|
|
__Found = true; \
|
|
break; \
|
|
} \
|
|
} \
|
|
assert(__Found && "invalid token supplied for " \
|
|
#CursorName ", expected one of {" #__VA_ARGS__ "}"); \
|
|
} \
|
|
})
|
|
#else
|
|
#define syntax_assert_child_token(Raw, CursorName, ...) ({});
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
#define syntax_assert_child_token_text(Raw, CursorName, TokenKind, ...) \
|
|
({ \
|
|
bool __Found = false; \
|
|
auto __Child = cast<RawTokenSyntax>(Raw->getChild(Cursor::CursorName)); \
|
|
if (__Child->isPresent()) { \
|
|
assert(__Child->getTokenKind() == TokenKind); \
|
|
for (auto __Text : {__VA_ARGS__}) { \
|
|
if (__Child->getText() == __Text) { \
|
|
__Found = true; \
|
|
break; \
|
|
} \
|
|
} \
|
|
assert(__Found && "invalid text supplied for " \
|
|
#CursorName ", expected one of {" #__VA_ARGS__ "}"); \
|
|
} \
|
|
})
|
|
#else
|
|
#define syntax_assert_child_token_text(Raw, CursorName, TokenKind, ...) ({});
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
#define syntax_assert_token_is(Tok, Kind, Text) \
|
|
({ \
|
|
assert(Tok.getTokenKind() == Kind); \
|
|
assert(Tok.getText() == Text); \
|
|
})
|
|
#else
|
|
#define syntax_assert_token_is(Tok, Kind, Text) ({});
|
|
#endif
|
|
|
|
namespace swift {
|
|
namespace syntax {
|
|
|
|
using CursorIndex = uint32_t;
|
|
|
|
/// Get a numeric index suitable for array/vector indexing
|
|
/// from a syntax node's Cursor enum value.
|
|
template <typename CursorType> constexpr CursorIndex cursorIndex(CursorType C) {
|
|
return static_cast<CursorIndex>(C);
|
|
}
|
|
|
|
/// An absolute position in a source file as text - the absolute offset from
|
|
/// the start, line, and column.
|
|
class AbsolutePosition {
|
|
uintptr_t Offset = 0;
|
|
uint32_t Line = 1;
|
|
uint32_t Column = 1;
|
|
|
|
public:
|
|
/// Add some number of columns to the position.
|
|
void addColumns(uint32_t Columns) {
|
|
Column += Columns;
|
|
Offset += Columns;
|
|
}
|
|
|
|
/// Add some number of newlines to the position, resetting the column.
|
|
void addNewlines(uint32_t NewLines) {
|
|
Line += NewLines;
|
|
Column = 1;
|
|
Offset += NewLines;
|
|
}
|
|
|
|
/// Use some text as a reference for adding to the absolute position,
|
|
/// taking note of newlines, etc.
|
|
void addText(StringRef Str) {
|
|
for (auto C : Str) {
|
|
addCharacter(C);
|
|
}
|
|
}
|
|
|
|
/// Use some character as a reference for adding to the absolute position,
|
|
/// taking note of newlines, etc.
|
|
void addCharacter(char C) {
|
|
if (C == '\n') {
|
|
addNewlines(1);
|
|
} else {
|
|
addColumns(1);
|
|
}
|
|
}
|
|
|
|
/// Get the line number of this position.
|
|
uint32_t getLine() const { return Line; }
|
|
|
|
/// Get the column number of this position.
|
|
uint32_t getColumn() const { return Column; }
|
|
|
|
/// Get the line and column number of this position.
|
|
std::pair<uint32_t, uint32_t> getLineAndColumn() const {
|
|
return {Line, Column};
|
|
}
|
|
|
|
/// Get the absolute offset of this position, suitable for indexing into a
|
|
/// buffer if applicable.
|
|
uintptr_t getOffset() const { return Offset; }
|
|
|
|
/// Print the line and column as "l:c" to the given output stream.
|
|
void printLineAndColumn(llvm::raw_ostream &OS) const;
|
|
|
|
/// Dump a description of this position to the given output stream
|
|
/// for debugging.
|
|
void dump(llvm::raw_ostream &OS = llvm::errs()) const;
|
|
};
|
|
|
|
/// An indicator of whether a Syntax node was found or written in the source.
|
|
///
|
|
/// This is not an 'implicit' bit.
|
|
enum class SourcePresence {
|
|
/// The syntax was authored by a human and found, or was generated.
|
|
Present,
|
|
|
|
/// The syntax was expected or optional, but not found in the source.
|
|
Missing,
|
|
};
|
|
|
|
/// The print option to specify when printing a raw syntax node.
|
|
struct SyntaxPrintOptions {
|
|
bool Visual = false;
|
|
bool PrintSyntaxKind = false;
|
|
};
|
|
|
|
/// RawSyntax - the strictly immutable, shared backing nodes for all syntax.
|
|
///
|
|
/// This is implementation detail - do not expose it in public API.
|
|
struct RawSyntax : public llvm::ThreadSafeRefCountedBase<RawSyntax> {
|
|
|
|
using LayoutList = std::vector<RC<RawSyntax>>;
|
|
|
|
/// The kind of syntax this node represents.
|
|
const SyntaxKind Kind;
|
|
|
|
/// The "layout" of the node - representing the children, or the terms
|
|
/// in the production of the grammar.
|
|
const LayoutList Layout;
|
|
|
|
/// Whether this piece of syntax was actually present in the source.
|
|
const SourcePresence Presence;
|
|
|
|
/// Create a piece of raw syntax.
|
|
RawSyntax(const SyntaxKind Kind, const std::vector<RC<RawSyntax>> Layout,
|
|
const SourcePresence Presence)
|
|
: Kind(Kind), Layout(Layout), Presence(Presence) {}
|
|
|
|
virtual ~RawSyntax() = default;
|
|
|
|
/// Returns a raw syntax node of the given Kind, specified Layout,
|
|
/// and source presence.
|
|
static RC<RawSyntax> make(const SyntaxKind Kind, const LayoutList Layout,
|
|
const SourcePresence Presence) {
|
|
return RC<RawSyntax>{new RawSyntax{Kind, Layout, Presence}};
|
|
}
|
|
|
|
/// Returns a raw syntax node of the given Kind, marked as missing.
|
|
static RC<RawSyntax> missing(const SyntaxKind Kind) {
|
|
return make(Kind, {}, SourcePresence::Missing);
|
|
}
|
|
|
|
/// Get a child based on a particular node's "Cursor", indicating
|
|
/// the position of the terms in the production of the Swift grammar.
|
|
template <typename CursorType> RC<RawSyntax> getChild(CursorType C) const {
|
|
return Layout[cursorIndex(C)];
|
|
}
|
|
|
|
/// Returns true if the node is "missing" in the source (i.e. it was
|
|
/// expected (or optional) but not written.
|
|
bool isMissing() const { return Presence == SourcePresence::Missing; }
|
|
|
|
/// Returns true if the node is "present" in the source.
|
|
bool isPresent() const {
|
|
return Presence == SourcePresence::Present;
|
|
}
|
|
|
|
/// Returns true if this raw syntax node is some kind of declaration.
|
|
bool isDecl() const { return isDeclKind(Kind); }
|
|
|
|
/// Returns true if this raw syntax node is some kind of type syntax.
|
|
bool isType() const { return isTypeKind(Kind); }
|
|
|
|
/// Returns true if this raw syntax node is some kind of statement.
|
|
bool isStmt() const { return isStmtKind(Kind); }
|
|
|
|
/// Returns true if this raw syntax node is some kind of expression.
|
|
bool isExpr() const { return isExprKind(Kind); }
|
|
|
|
/// Returns true if this raw syntax node is some kind of pattern.
|
|
bool isPattern() const { return isPatternKind(Kind); }
|
|
|
|
/// Return true if this raw syntax node is a token.
|
|
bool isToken() const { return isTokenKind(Kind); }
|
|
|
|
bool isUnknown() const { return isUnknownKind(Kind); }
|
|
|
|
/// Get the absolute position of this raw syntax: its offset, line,
|
|
/// and column.
|
|
AbsolutePosition getAbsolutePosition(RC<RawSyntax> Root) const;
|
|
|
|
/// Return a new raw syntax node with the given new layout element appended
|
|
/// to the end of the node's layout.
|
|
RC<RawSyntax> append(RC<RawSyntax> NewLayoutElement) const;
|
|
|
|
/// Return a new raw syntax node with the given new layout element replacing
|
|
/// another at some cursor position.
|
|
template <typename CursorType>
|
|
RC<RawSyntax>
|
|
replaceChild(CursorType C, RC<RawSyntax> NewLayoutElement) const {
|
|
LayoutList NewLayout;
|
|
|
|
std::copy(Layout.begin(), Layout.begin() + cursorIndex(C),
|
|
std::back_inserter(NewLayout));
|
|
|
|
NewLayout.push_back(NewLayoutElement);
|
|
|
|
std::copy(Layout.begin() + cursorIndex(C) + 1, Layout.end(),
|
|
std::back_inserter(NewLayout));
|
|
|
|
return RawSyntax::make(Kind, NewLayout, Presence);
|
|
}
|
|
|
|
/// Print this piece of syntax recursively.
|
|
void print(llvm::raw_ostream &OS, SyntaxPrintOptions Opts) const;
|
|
|
|
/// Dump this piece of syntax recursively for debugging or testing.
|
|
void dump() const;
|
|
|
|
/// Dump this piece of syntax recursively.
|
|
void dump(llvm::raw_ostream &OS, unsigned Indent) const;
|
|
|
|
private:
|
|
bool accumulateAbsolutePosition(AbsolutePosition &Pos,
|
|
const RawSyntax *UpToTargetNode) const;
|
|
};
|
|
|
|
} // end namespace syntax
|
|
} // end namespace swift
|
|
|
|
#endif // SWIFT_SYNTAX_RAWSYNTAX_H
|