//===--- 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 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 { ArrayRef Children; }; 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, ArrayRef deferredNodes) : DeferredLayout{deferredNodes}, 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!"); } 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) : RecordedData{n, r}, SynKind(uint16_t(k)), TokKind(uint16_t(tokKind)), DK(DataKind::Recorded) { assert(getKind() == k && "Syntax kind with too large value!"); assert(getTokenKind() == tokKind && "Token kind with too large value!"); } 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; } // Recorded Data ===========================================================// CharSourceRange getRange() const { assert(isRecorded()); return RecordedData.Range; } OpaqueSyntaxNode getOpaqueNode() const { assert(isRecorded()); return RecordedData.OpaqueNode; } // Deferred Layout Data ====================================================// ArrayRef getDeferredChildren() const { assert(DK == DataKind::DeferredLayout); return DeferredLayout.Children; } // Deferred Token Data =====================================================// CharSourceRange getDeferredTokenRangeWithoutBackticks() const { assert(DK == DataKind::DeferredToken); return CharSourceRange{DeferredToken.TokLoc, DeferredToken.TokLength}; } ArrayRef getDeferredLeadingTriviaPieces() const { assert(DK == DataKind::DeferredToken); return ArrayRef(DeferredToken.TriviaPieces, DeferredToken.NumLeadingTrivia); } ArrayRef getDeferredTrailingTriviaPieces() const { assert(DK == DataKind::DeferredToken); return ArrayRef( DeferredToken.TriviaPieces + DeferredToken.NumLeadingTrivia, DeferredToken.NumTrailingTrivia); } //==========================================================================// /// Form a deferred syntax layout node. static ParsedRawSyntaxNode makeDeferred(syntax::SyntaxKind k, ArrayRef 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