//===--- 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/SyntaxParsingContext.h" #include "swift/Parse/Token.h" #include "swift/Syntax/SyntaxKind.h" using namespace swift; using namespace swift::syntax; ParsedRawSyntaxNode ParsedRawSyntaxRecorder::recordToken(const Token &tok, StringRef leadingTrivia, StringRef trailingTrivia) { return recordToken(tok.getKind(), tok.getRange(), leadingTrivia, trailingTrivia); } ParsedRawSyntaxNode ParsedRawSyntaxRecorder::recordToken(tok tokKind, CharSourceRange tokRange, StringRef leadingTrivia, StringRef trailingTrivia) { SourceLoc offset = tokRange.getStart().getAdvancedLoc(-leadingTrivia.size()); unsigned length = leadingTrivia.size() + tokRange.getByteLength() + trailingTrivia.size(); 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.getDeferredLeadingTrivia(), node.getDeferredTrailingTrivia()); } ParsedRawSyntaxNode ParsedRawSyntaxRecorder::recordRawSyntax(SyntaxKind kind, MutableArrayRef elements) { #ifndef NDEBUG ParsedRawSyntaxRecorder::verifyElementRanges(elements); #endif CharSourceRange range; SmallVector 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}; } /// Create a deferred layout node. ParsedRawSyntaxNode ParsedRawSyntaxRecorder::makeDeferred( syntax::SyntaxKind k, MutableArrayRef deferredNodes, SyntaxParsingContext &ctx) { CharSourceRange range; if (deferredNodes.empty()) { return ParsedRawSyntaxNode(k, range, {}); } ParsedRawSyntaxNode *newPtr = ctx.getScratchAlloc().Allocate(deferredNodes.size()); #ifndef NDEBUG ParsedRawSyntaxRecorder::verifyElementRanges(deferredNodes); #endif auto ptr = newPtr; for (auto &node : deferredNodes) { // Cached range. if (!node.isNull() && !node.isMissing()) { auto nodeRange = node.getDeferredRange(); if (nodeRange.isValid()) { if (range.isInvalid()) range = nodeRange; else range.widen(nodeRange); } } // uninitialized move; ::new (static_cast(ptr++)) ParsedRawSyntaxNode(std::move(node)); } return ParsedRawSyntaxNode( k, range, llvm::makeMutableArrayRef(newPtr, deferredNodes.size())); } /// Create a deferred token node. ParsedRawSyntaxNode ParsedRawSyntaxRecorder::makeDeferred(Token tok, StringRef leadingTrivia, StringRef trailingTrivia) { CharSourceRange tokRange = tok.getRange(); return ParsedRawSyntaxNode(tok.getKind(), tokRange.getStart(), tokRange.getByteLength(), leadingTrivia, trailingTrivia); } ParsedRawSyntaxNode ParsedRawSyntaxRecorder::makeDeferredMissing(tok tokKind, SourceLoc loc) { auto raw = ParsedRawSyntaxNode(tokKind, loc, /*tokLength=*/0, /*leadingTrivia=*/StringRef(), /*trailingTrivia=*/StringRef()); raw.IsMissing = true; return raw; } 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 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