blob: b1cd4035a27126ad5d5cf650b97bca6ac464c055 [file] [log] [blame]
//===--- ParsedRawSyntaxNode.h - Parsed Raw Syntax Node ---------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 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
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_PARSE_PARSEDRAWSYNTAXNODE_H
#define SWIFT_PARSE_PARSEDRAWSYNTAXNODE_H
#include "swift/Basic/SourceLoc.h"
#include "swift/Parse/ParsedTrivia.h"
#include "swift/Parse/Token.h"
#include "swift/Syntax/SyntaxKind.h"
#include <vector>
namespace swift {
typedef void *OpaqueSyntaxNode;
class SyntaxParsingContext;
/// Represents a raw syntax node formed by the parser.
///
/// It can be either 'recorded', in which case it encapsulates an
/// \c OpaqueSyntaxNode that was returned from a \c SyntaxParseActions
/// invocation, or 'deferred' which captures the data for a
/// \c SyntaxParseActions invocation to occur later.
///
/// An \c OpaqueSyntaxNode can represent both the result of 'recording' a token
/// as well as 'recording' a syntax layout, so there's only one
/// \c RecordedSyntaxNode structure that can represent both.
///
/// The 'deferred' form is used for when the parser is backtracking and when
/// there are instances that it's not clear what will be the final syntax node
/// in the current parsing context.
class ParsedRawSyntaxNode {
enum class DataKind: uint8_t {
Null,
Recorded,
DeferredLayout,
DeferredToken,
};
struct RecordedSyntaxNode {
OpaqueSyntaxNode OpaqueNode;
CharSourceRange Range;
};
struct DeferredLayoutNode {
MutableArrayRef<ParsedRawSyntaxNode> Children;
CharSourceRange Range;
};
struct DeferredTokenNode {
const ParsedTriviaPiece *TriviaPieces;
SourceLoc TokLoc;
unsigned TokLength;
uint16_t NumLeadingTrivia;
uint16_t NumTrailingTrivia;
};
union {
RecordedSyntaxNode RecordedData;
DeferredLayoutNode DeferredLayout;
DeferredTokenNode DeferredToken;
};
uint16_t SynKind;
uint16_t TokKind;
DataKind DK;
/// Primary used for capturing a deferred missing token.
bool IsMissing = false;
ParsedRawSyntaxNode(syntax::SyntaxKind k, CharSourceRange r,
MutableArrayRef<ParsedRawSyntaxNode> deferredNodes)
: DeferredLayout({deferredNodes, r}),
SynKind(uint16_t(k)), TokKind(uint16_t(tok::unknown)),
DK(DataKind::DeferredLayout) {
assert(getKind() == k && "Syntax kind with too large value!");
}
ParsedRawSyntaxNode(tok tokKind, SourceLoc tokLoc, unsigned tokLength,
const ParsedTriviaPiece *triviaPieces,
unsigned numLeadingTrivia,
unsigned numTrailingTrivia)
: DeferredToken{triviaPieces,
tokLoc, tokLength,
uint16_t(numLeadingTrivia),
uint16_t(numTrailingTrivia)},
SynKind(uint16_t(syntax::SyntaxKind::Token)),
TokKind(uint16_t(tokKind)),
DK(DataKind::DeferredToken) {
assert(getTokenKind() == tokKind && "Token kind is too large value!");
assert(DeferredToken.NumLeadingTrivia == numLeadingTrivia &&
"numLeadingTrivia is too large value!");
assert(DeferredToken.NumTrailingTrivia == numTrailingTrivia &&
"numLeadingTrivia is too large value!");
}
ParsedRawSyntaxNode(ParsedRawSyntaxNode &other) = delete;
ParsedRawSyntaxNode &operator=(ParsedRawSyntaxNode &other) = delete;
public:
ParsedRawSyntaxNode()
: RecordedData{},
SynKind(uint16_t(syntax::SyntaxKind::Unknown)),
TokKind(uint16_t(tok::unknown)),
DK(DataKind::Null) {
}
ParsedRawSyntaxNode(syntax::SyntaxKind k, tok tokKind,
CharSourceRange r, OpaqueSyntaxNode n,
bool IsMissing = false)
: RecordedData{n, r},
SynKind(uint16_t(k)), TokKind(uint16_t(tokKind)),
DK(DataKind::Recorded),
IsMissing(IsMissing) {
assert(getKind() == k && "Syntax kind with too large value!");
assert(getTokenKind() == tokKind && "Token kind with too large value!");
}
#ifndef NDEBUG
bool ensureDataIsNotRecorded() {
if (DK != DataKind::Recorded)
return true;
llvm::dbgs() << "Leaking node: ";
dump(llvm::dbgs());
llvm::dbgs() << "\n";
return false;
}
#endif
ParsedRawSyntaxNode &operator=(ParsedRawSyntaxNode &&other) {
assert(ensureDataIsNotRecorded() &&
"recorded data is being destroyed by assignment");
switch (other.DK) {
case DataKind::Null:
break;
case DataKind::Recorded:
RecordedData = std::move(other.RecordedData);
break;
case DataKind::DeferredLayout:
DeferredLayout = std::move(other.DeferredLayout);
break;
case DataKind::DeferredToken:
DeferredToken = std::move(other.DeferredToken);
break;
}
SynKind = std::move(other.SynKind);
TokKind = std::move(other.TokKind);
DK = std::move(other.DK);
IsMissing = std::move(other.IsMissing);
other.reset();
return *this;
}
ParsedRawSyntaxNode(ParsedRawSyntaxNode &&other) : ParsedRawSyntaxNode() {
*this = std::move(other);
}
~ParsedRawSyntaxNode() {
assert(ensureDataIsNotRecorded() && "recorded data is being destructed");
}
syntax::SyntaxKind getKind() const { return syntax::SyntaxKind(SynKind); }
tok getTokenKind() const { return tok(TokKind); }
bool isToken() const {
return getKind() == syntax::SyntaxKind::Token;
}
bool isToken(tok tokKind) const {
return getTokenKind() == tokKind;
}
bool isNull() const {
return DK == DataKind::Null;
}
bool isRecorded() const { return DK == DataKind::Recorded; }
bool isDeferredLayout() const { return DK == DataKind::DeferredLayout; }
bool isDeferredToken() const { return DK == DataKind::DeferredToken; }
/// Primary used for a deferred missing token.
bool isMissing() const { return IsMissing; }
void reset() {
RecordedData = {};
SynKind = uint16_t(syntax::SyntaxKind::Unknown);
TokKind = uint16_t(tok::unknown);
DK = DataKind::Null;
IsMissing = false;
}
ParsedRawSyntaxNode unsafeCopy() const {
ParsedRawSyntaxNode copy;
switch (DK) {
case DataKind::DeferredLayout:
copy.DeferredLayout = DeferredLayout;
break;
case DataKind::DeferredToken:
copy.DeferredToken = DeferredToken;
break;
case DataKind::Recorded:
copy.RecordedData = RecordedData;
break;
case DataKind::Null:
break;
}
copy.SynKind = SynKind;
copy.TokKind = TokKind;
copy.DK = DK;
copy.IsMissing = IsMissing;
return copy;
}
CharSourceRange getDeferredRange() const {
switch (DK) {
case DataKind::DeferredLayout:
return getDeferredLayoutRange();
case DataKind::DeferredToken:
return getDeferredTokenRangeWithTrivia();
default:
llvm_unreachable("node not deferred");
}
}
// Recorded Data ===========================================================//
CharSourceRange getRecordedRange() const {
assert(isRecorded());
return RecordedData.Range;
}
const OpaqueSyntaxNode &getOpaqueNode() const {
assert(isRecorded());
return RecordedData.OpaqueNode;
}
OpaqueSyntaxNode takeOpaqueNode() {
assert(isRecorded());
auto opaque = RecordedData.OpaqueNode;
reset();
return opaque;
}
// Deferred Layout Data ====================================================//
CharSourceRange getDeferredLayoutRange() const {
assert(DK == DataKind::DeferredLayout);
return DeferredLayout.Range;
}
ArrayRef<ParsedRawSyntaxNode> getDeferredChildren() const {
assert(DK == DataKind::DeferredLayout);
return DeferredLayout.Children;
}
MutableArrayRef<ParsedRawSyntaxNode> getDeferredChildren() {
assert(DK == DataKind::DeferredLayout);
return DeferredLayout.Children;
}
ParsedRawSyntaxNode copyDeferred() const {
ParsedRawSyntaxNode copy;
switch (DK) {
case DataKind::DeferredLayout:
copy.DeferredLayout = DeferredLayout;
break;
case DataKind::DeferredToken:
copy.DeferredToken = DeferredToken;
break;
default:
llvm_unreachable("node not deferred");
}
copy.SynKind = SynKind;
copy.TokKind = TokKind;
copy.DK = DK;
copy.IsMissing = IsMissing;
return copy;
}
// Deferred Token Data =====================================================//
CharSourceRange getDeferredTokenRangeWithTrivia() const {
assert(DK == DataKind::DeferredToken);
auto leadTriviaPieces = getDeferredLeadingTriviaPieces();
auto trailTriviaPieces = getDeferredTrailingTriviaPieces();
auto leadTriviaLen = ParsedTriviaPiece::getTotalLength(leadTriviaPieces);
auto trailTriviaLen = ParsedTriviaPiece::getTotalLength(trailTriviaPieces);
SourceLoc begin = DeferredToken.TokLoc.getAdvancedLoc(-leadTriviaLen);
unsigned len = leadTriviaLen + DeferredToken.TokLength + trailTriviaLen;
return CharSourceRange{begin, len};
}
CharSourceRange getDeferredTokenRange() const {
assert(DK == DataKind::DeferredToken);
return CharSourceRange{DeferredToken.TokLoc, DeferredToken.TokLength};
}
ArrayRef<ParsedTriviaPiece> getDeferredLeadingTriviaPieces() const {
assert(DK == DataKind::DeferredToken);
return ArrayRef<ParsedTriviaPiece>(DeferredToken.TriviaPieces,
DeferredToken.NumLeadingTrivia);
}
ArrayRef<ParsedTriviaPiece> getDeferredTrailingTriviaPieces() const {
assert(DK == DataKind::DeferredToken);
return ArrayRef<ParsedTriviaPiece>(
DeferredToken.TriviaPieces + DeferredToken.NumLeadingTrivia,
DeferredToken.NumTrailingTrivia);
}
//==========================================================================//
/// Form a deferred syntax layout node.
static ParsedRawSyntaxNode makeDeferred(syntax::SyntaxKind k,
MutableArrayRef<ParsedRawSyntaxNode> deferredNodes,
SyntaxParsingContext &ctx);
/// Form a deferred token node.
static ParsedRawSyntaxNode makeDeferred(Token tok,
const ParsedTrivia &leadingTrivia,
const ParsedTrivia &trailingTrivia,
SyntaxParsingContext &ctx);
/// Form a deferred missing token node.
static ParsedRawSyntaxNode makeDeferredMissing(tok tokKind, SourceLoc loc) {
auto raw = ParsedRawSyntaxNode(tokKind, loc, 0, nullptr, 0, 0);
raw.IsMissing = true;
return raw;
}
/// Dump this piece of syntax recursively for debugging or testing.
LLVM_ATTRIBUTE_DEPRECATED(
void dump() const LLVM_ATTRIBUTE_USED,
"only for use within the debugger");
/// Dump this piece of syntax recursively.
void dump(raw_ostream &OS, unsigned Indent = 0) const;
static ParsedRawSyntaxNode null() {
return ParsedRawSyntaxNode{};
}
};
} // end namespace swift
#endif