| //===--- SyntaxTreeCreator.cpp - Syntax Tree Creation ----------*- 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 |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "swift/SyntaxParse/SyntaxTreeCreator.h" |
| #include "swift/Syntax/RawSyntax.h" |
| #include "swift/Syntax/SyntaxVisitor.h" |
| #include "swift/Syntax/Trivia.h" |
| #include "swift/Parse/ParsedTrivia.h" |
| #include "swift/Parse/SyntaxParsingCache.h" |
| #include "swift/Parse/Token.h" |
| #include "swift/AST/ASTContext.h" |
| #include "swift/AST/DiagnosticsParse.h" |
| #include "swift/AST/Module.h" |
| #include "swift/Basic/OwnedString.h" |
| #include "RawSyntaxTokenCache.h" |
| |
| using namespace swift; |
| using namespace swift::syntax; |
| |
| static RC<RawSyntax> transferOpaqueNode(OpaqueSyntaxNode opaqueN) { |
| if (!opaqueN) |
| return nullptr; |
| RC<RawSyntax> raw{(RawSyntax *)opaqueN}; |
| raw->Release(); // -1 since it's transfer of ownership. |
| return raw; |
| } |
| |
| SyntaxTreeCreator::SyntaxTreeCreator(SourceManager &SM, unsigned bufferID, |
| SyntaxParsingCache *syntaxCache, |
| RC<syntax::SyntaxArena> arena) |
| : SM(SM), BufferID(bufferID), |
| Arena(std::move(arena)), |
| SyntaxCache(syntaxCache), |
| TokenCache(new RawSyntaxTokenCache()) { |
| } |
| |
| SyntaxTreeCreator::~SyntaxTreeCreator() = default; |
| |
| namespace { |
| /// This verifier traverses a syntax node to emit proper diagnostics. |
| class SyntaxVerifier: public SyntaxVisitor { |
| SourceManager &SourceMgr; |
| unsigned BufferID; |
| DiagnosticEngine &Diags; |
| |
| template<class T> |
| SourceLoc getSourceLoc(T Node) { |
| return SourceMgr.getLocForOffset(BufferID, |
| Node.getAbsolutePosition().getOffset()); |
| } |
| public: |
| SyntaxVerifier( SourceManager &SM, unsigned bufID, DiagnosticEngine &diags) |
| : SourceMgr(SM), BufferID(bufID), Diags(diags) {} |
| |
| void visit(UnknownDeclSyntax Node) override { |
| Diags.diagnose(getSourceLoc(Node), diag::unknown_syntax_entity, |
| "declaration"); |
| visitChildren(Node); |
| } |
| void visit(UnknownExprSyntax Node) override { |
| Diags.diagnose(getSourceLoc(Node), diag::unknown_syntax_entity, |
| "expression"); |
| visitChildren(Node); |
| } |
| void visit(UnknownStmtSyntax Node) override { |
| Diags.diagnose(getSourceLoc(Node), diag::unknown_syntax_entity, |
| "statement"); |
| visitChildren(Node); |
| } |
| void visit(UnknownTypeSyntax Node) override { |
| Diags.diagnose(getSourceLoc(Node), diag::unknown_syntax_entity, |
| "type"); |
| visitChildren(Node); |
| } |
| void visit(UnknownPatternSyntax Node) override { |
| Diags.diagnose(getSourceLoc(Node), diag::unknown_syntax_entity, |
| "pattern"); |
| visitChildren(Node); |
| } |
| void verify(Syntax Node) { |
| Node.accept(*this); |
| } |
| }; |
| } // anonymous namespace |
| |
| void SyntaxTreeCreator::acceptSyntaxRoot(OpaqueSyntaxNode rootN, |
| SourceFile &SF) { |
| auto raw = transferOpaqueNode(rootN); |
| SF.setSyntaxRoot(make<SourceFileSyntax>(raw)); |
| |
| // Verify the tree if specified. |
| if (SF.getASTContext().LangOpts.VerifySyntaxTree) { |
| ASTContext &ctx = SF.getASTContext(); |
| SyntaxVerifier Verifier(ctx.SourceMgr, SF.getBufferID().getValue(), |
| ctx.Diags); |
| Verifier.verify(SF.getSyntaxRoot()); |
| } |
| } |
| |
| OpaqueSyntaxNode |
| SyntaxTreeCreator::recordToken(tok tokenKind, |
| ArrayRef<ParsedTriviaPiece> leadingTriviaPieces, |
| ArrayRef<ParsedTriviaPiece> trailingTriviaPieces, |
| CharSourceRange range) { |
| size_t leadingTriviaLen = |
| ParsedTriviaPiece::getTotalLength(leadingTriviaPieces); |
| size_t trailingTriviaLen = |
| ParsedTriviaPiece::getTotalLength(trailingTriviaPieces); |
| SourceLoc tokLoc = range.getStart().getAdvancedLoc(leadingTriviaLen); |
| unsigned tokLength = range.getByteLength() - |
| leadingTriviaLen - trailingTriviaLen; |
| CharSourceRange tokRange = CharSourceRange{tokLoc, tokLength}; |
| SourceLoc leadingTriviaLoc = range.getStart(); |
| SourceLoc trailingTriviaLoc = tokLoc.getAdvancedLoc(tokLength); |
| Trivia syntaxLeadingTrivia = |
| ParsedTriviaPiece::convertToSyntaxTrivia(leadingTriviaPieces, |
| leadingTriviaLoc, SM, BufferID); |
| Trivia syntaxTrailingTrivia = |
| ParsedTriviaPiece::convertToSyntaxTrivia(trailingTriviaPieces, |
| trailingTriviaLoc, SM, BufferID); |
| StringRef tokenText = SM.extractText(tokRange, BufferID); |
| auto ownedText = OwnedString::makeRefCounted(tokenText); |
| auto raw = TokenCache->getToken(Arena, tokenKind, ownedText, |
| syntaxLeadingTrivia.Pieces, syntaxTrailingTrivia.Pieces); |
| OpaqueSyntaxNode opaqueN = raw.get(); |
| raw.resetWithoutRelease(); |
| return opaqueN; |
| } |
| |
| OpaqueSyntaxNode |
| SyntaxTreeCreator::recordMissingToken(tok kind, SourceLoc loc) { |
| auto ownedText = OwnedString::makeRefCounted(getTokenText(kind)); |
| auto raw = RawSyntax::missing(kind, ownedText, Arena); |
| OpaqueSyntaxNode opaqueN = raw.get(); |
| raw.resetWithoutRelease(); |
| return opaqueN; |
| } |
| |
| OpaqueSyntaxNode |
| SyntaxTreeCreator::recordRawSyntax(syntax::SyntaxKind kind, |
| ArrayRef<OpaqueSyntaxNode> elements, |
| CharSourceRange range) { |
| SmallVector<RC<RawSyntax>, 16> parts; |
| parts.reserve(elements.size()); |
| for (OpaqueSyntaxNode opaqueN : elements) { |
| parts.push_back(transferOpaqueNode(opaqueN)); |
| } |
| auto raw = RawSyntax::make(kind, parts, SourcePresence::Present, Arena); |
| OpaqueSyntaxNode opaqueN = raw.get(); |
| raw.resetWithoutRelease(); |
| return opaqueN; |
| } |
| |
| std::pair<size_t, OpaqueSyntaxNode> |
| SyntaxTreeCreator::lookupNode(size_t lexerOffset, syntax::SyntaxKind kind) { |
| if (!SyntaxCache) |
| return {0, nullptr}; |
| auto cacheLookup = SyntaxCache->lookUp(lexerOffset, kind); |
| if (!cacheLookup) |
| return {0, nullptr}; |
| RC<RawSyntax> raw = cacheLookup->getRaw(); |
| OpaqueSyntaxNode opaqueN = raw.get(); |
| size_t length = raw->getTextLength(); |
| raw.resetWithoutRelease(); |
| return {length, opaqueN}; |
| } |