| //===--- ParsedRawSyntaxRecorder.cpp - Raw Syntax Parsing Recorder --------===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines the ParsedRawSyntaxRecorder, which is the interface the |
| // parser is using to pass parsed syntactic elements to a SyntaxParseActions |
| // receiver and get a ParsedRawSyntaxNode object back. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "swift/Parse/ParsedRawSyntaxRecorder.h" |
| #include "swift/Parse/ParsedRawSyntaxNode.h" |
| #include "swift/Parse/ParsedTrivia.h" |
| #include "swift/Parse/SyntaxParseActions.h" |
| #include "swift/Parse/Token.h" |
| #include "swift/Syntax/SyntaxKind.h" |
| |
| using namespace swift; |
| using namespace swift::syntax; |
| |
| ParsedRawSyntaxNode |
| ParsedRawSyntaxRecorder::recordToken(const Token &tok, |
| const ParsedTrivia &leadingTrivia, |
| const ParsedTrivia &trailingTrivia) { |
| return recordToken(tok.getKind(), tok.getRange(), |
| leadingTrivia.Pieces, trailingTrivia.Pieces); |
| } |
| |
| ParsedRawSyntaxNode |
| ParsedRawSyntaxRecorder::recordToken(tok tokKind, CharSourceRange tokRange, |
| ArrayRef<ParsedTriviaPiece> leadingTrivia, |
| ArrayRef<ParsedTriviaPiece> trailingTrivia) { |
| size_t leadingTriviaLen = ParsedTriviaPiece::getTotalLength(leadingTrivia); |
| size_t trailingTriviaLen = ParsedTriviaPiece::getTotalLength(trailingTrivia); |
| SourceLoc offset = tokRange.getStart().getAdvancedLoc(-leadingTriviaLen); |
| unsigned length = leadingTriviaLen + tokRange.getByteLength() + |
| trailingTriviaLen; |
| CharSourceRange range{offset, length}; |
| OpaqueSyntaxNode n = SPActions->recordToken(tokKind, leadingTrivia, |
| trailingTrivia, range); |
| return ParsedRawSyntaxNode{SyntaxKind::Token, tokKind, range, n}; |
| } |
| |
| ParsedRawSyntaxNode |
| ParsedRawSyntaxRecorder::recordMissingToken(tok tokenKind, SourceLoc loc) { |
| CharSourceRange range{loc, 0}; |
| OpaqueSyntaxNode n = SPActions->recordMissingToken(tokenKind, loc); |
| return ParsedRawSyntaxNode{SyntaxKind::Token, tokenKind, range, n, |
| /*isMissing=*/true}; |
| } |
| |
| static ParsedRawSyntaxNode |
| getRecordedNode(ParsedRawSyntaxNode node, ParsedRawSyntaxRecorder &rec) { |
| assert(!node.isNull() && !node.isRecorded()); |
| if (node.isDeferredLayout()) |
| return rec.recordRawSyntax(node.getKind(), node.getDeferredChildren()); |
| assert(node.isDeferredToken()); |
| CharSourceRange tokRange = node.getDeferredTokenRange(); |
| tok tokKind = node.getTokenKind(); |
| if (node.isMissing()) |
| return rec.recordMissingToken(tokKind, tokRange.getStart()); |
| return rec.recordToken(tokKind,tokRange, |
| node.getDeferredLeadingTriviaPieces(), |
| node.getDeferredTrailingTriviaPieces()); |
| } |
| |
| ParsedRawSyntaxNode |
| ParsedRawSyntaxRecorder::recordRawSyntax(SyntaxKind kind, |
| MutableArrayRef<ParsedRawSyntaxNode> elements) { |
| CharSourceRange range; |
| SmallVector<OpaqueSyntaxNode, 16> subnodes; |
| if (!elements.empty()) { |
| SourceLoc offset; |
| unsigned length = 0; |
| for (auto &subnode : elements) { |
| CharSourceRange localRange; |
| if (subnode.isNull()) { |
| subnodes.push_back(nullptr); |
| } else if (subnode.isRecorded()) { |
| localRange = subnode.getRecordedRange(); |
| subnodes.push_back(subnode.takeOpaqueNode()); |
| } else { |
| auto recorded = getRecordedNode(subnode.copyDeferred(), *this); |
| localRange = recorded.getRecordedRange(); |
| subnodes.push_back(recorded.takeOpaqueNode()); |
| } |
| |
| if (localRange.isValid()) { |
| if (offset.isInvalid()) |
| offset = localRange.getStart(); |
| length += localRange.getByteLength(); |
| } |
| } |
| range = CharSourceRange{offset, length}; |
| } |
| OpaqueSyntaxNode n = SPActions->recordRawSyntax(kind, subnodes, range); |
| return ParsedRawSyntaxNode{kind, tok::unknown, range, n}; |
| } |
| |
| ParsedRawSyntaxNode |
| ParsedRawSyntaxRecorder::recordEmptyRawSyntaxCollection(SyntaxKind kind, |
| SourceLoc loc) { |
| CharSourceRange range{loc, 0}; |
| OpaqueSyntaxNode n = SPActions->recordRawSyntax(kind, {}, range); |
| return ParsedRawSyntaxNode{kind, tok::unknown, range, n}; |
| } |
| |
| void ParsedRawSyntaxRecorder::discardRecordedNode(ParsedRawSyntaxNode &node) { |
| SPActions->discardRecordedNode(node.takeOpaqueNode()); |
| } |
| |
| ParsedRawSyntaxNode |
| ParsedRawSyntaxRecorder::lookupNode(size_t lexerOffset, SourceLoc loc, |
| SyntaxKind kind) { |
| size_t length; |
| OpaqueSyntaxNode n; |
| std::tie(length, n) = SPActions->lookupNode(lexerOffset, kind); |
| if (length == 0) { |
| return ParsedRawSyntaxNode::null(); |
| } |
| CharSourceRange range{loc, unsigned(length)}; |
| return ParsedRawSyntaxNode{kind, tok::unknown, range, n}; |
| } |
| |
| #ifndef NDEBUG |
| void ParsedRawSyntaxRecorder::verifyElementRanges(ArrayRef<ParsedRawSyntaxNode> elements) { |
| SourceLoc prevEndLoc; |
| for (const auto &elem: elements) { |
| if (elem.isMissing() || elem.isNull()) |
| continue; |
| CharSourceRange range = elem.isRecorded() |
| ? elem.getRecordedRange() |
| : elem.getDeferredRange(); |
| if (range.isValid()) { |
| assert((prevEndLoc.isInvalid() || range.getStart() == prevEndLoc) |
| && "Non-contiguous child ranges?"); |
| prevEndLoc = range.getEnd(); |
| } |
| } |
| } |
| #endif |