blob: af28b2c8277886d9edd1aa0ab32817b892cf1c69 [file] [log] [blame]
//===--- SyntaxParsingContext.cpp - Syntax Tree Parsing Support------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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/AST/Module.h"
#include "swift/Basic/Defer.h"
#include "swift/Parse/Token.h"
#include "swift/Parse/Parser.h"
#include "swift/Syntax/RawTokenSyntax.h"
#include "swift/Syntax/TokenSyntax.h"
#include "swift/Syntax/References.h"
#include "swift/Syntax/RawSyntax.h"
#include "swift/Syntax/Syntax.h"
#include "swift/Syntax/TokenKinds.h"
#include "swift/Syntax/Trivia.h"
#include "swift/Syntax/SyntaxParsingContext.h"
#include "swift/Syntax/SyntaxFactory.h"
using namespace swift;
using namespace swift::syntax;
namespace {
static Syntax makeUnknownSyntax(SyntaxKind Kind, ArrayRef<Syntax> SubExpr) {
assert(isUnknownKind(Kind));
RawSyntax::LayoutList Layout;
std::transform(SubExpr.begin(), SubExpr.end(), std::back_inserter(Layout),
[](const Syntax &S) { return S.getRaw(); });
return make<Syntax>(RawSyntax::make(Kind, Layout, SourcePresence::Present));
}
static ArrayRef<Syntax> getSyntaxNodes(ArrayRef<RawSyntaxInfo> RawNodes,
llvm::SmallVectorImpl<Syntax> &Scratch) {
std::transform(RawNodes.begin(), RawNodes.end(), std::back_inserter(Scratch),
[](const RawSyntaxInfo &Info) { return Info.makeSyntax<Syntax>(); });
return Scratch;
}
static SourceRange getNodesRange(ArrayRef<RawSyntaxInfo> RawNodes) {
SourceLoc StartLoc, EndLoc;
for (auto Info: RawNodes) {
if (Info.isImplicit())
continue;
if (StartLoc.isInvalid()) {
StartLoc = Info.getStartLoc();
}
EndLoc = Info.getEndLoc();
}
assert(StartLoc.isValid() == EndLoc.isValid());
return SourceRange(StartLoc, EndLoc);
}
static RawSyntaxInfo createSyntaxAs(ArrayRef<RawSyntaxInfo> Parts,
SyntaxKind Kind) {
llvm::SmallVector<Syntax, 8> Scratch;
auto SyntaxParts = getSyntaxNodes(Parts, Scratch);
// Try to create the node of the given syntax.
Optional<Syntax> Result = SyntaxFactory::createSyntax(Kind, SyntaxParts);
if (!Result) {
// If unable to create, we should create an unknown node.
Result.emplace(makeUnknownSyntax(SyntaxFactory::getUnknownKind(Kind),
SyntaxParts));
}
return { getNodesRange(Parts), Result->getRaw() };
}
} // End of anonymous namespace
struct SyntaxParsingContext::ContextInfo {
bool Enabled;
private:
SourceLoc ContextStartLoc;
std::vector<RawSyntaxInfo> PendingSyntax;
// All tokens after the start of this context.
ArrayRef<RawSyntaxInfo> Tokens;
ArrayRef<RawSyntaxInfo>::const_iterator findTokenAt(SourceLoc Loc) const {
for (auto It = Tokens.begin(); It != Tokens.end(); It ++) {
assert(It->getStartLoc() == It->getEndLoc());
if (It->getStartLoc() == Loc)
return It;
}
llvm_unreachable("cannot find the token on the given location");
}
public:
ContextInfo(SourceFile &File, unsigned BufferID):
Enabled(File.shouldKeepSyntaxInfo()) {
if (Enabled) {
populateTokenSyntaxMap(File.getASTContext().LangOpts,
File.getASTContext().SourceMgr,
BufferID, File.AllRawTokenSyntax);
Tokens = File.AllRawTokenSyntax;
assert(Tokens.back().makeSyntax<TokenSyntax>().getTokenKind() == tok::eof);
}
}
ContextInfo(ArrayRef<RawSyntaxInfo> Tokens, bool Enabled): Enabled(Enabled) {
if (Enabled) {
this->Tokens = Tokens;
}
}
// Squash N syntax nodex from the back of the pending list into one.
void createPartiallyFromBack(SyntaxKind Kind, ArrayRef<RawSyntaxInfo> UsedTokens,
unsigned N);
void createWhole(SyntaxKind Kind, ArrayRef<RawSyntaxInfo> NodesToUse);
std::vector<RawSyntaxInfo> collectAllSyntax(SourceLoc EndLoc);
ArrayRef<RawSyntaxInfo> allTokens() const { return Tokens; }
ArrayRef<RawSyntaxInfo> getPendingSyntax() const { return PendingSyntax; }
SourceLoc getContextStartLoc() const { return ContextStartLoc; }
void addPendingSyntax(RawSyntaxInfo Info) {
assert(Info.isImplicit() || PendingSyntax.empty() ||
PendingSyntax.back().getStartLoc().getOpaquePointerValue() <
Info.getStartLoc().getOpaquePointerValue());
assert(!Info.RawNode->isToken() && "Pending syntax should not have tokens");
PendingSyntax.push_back(Info);
}
void setContextStart(SourceLoc Loc) {
assert(ContextStartLoc.isInvalid());
ContextStartLoc = Loc;
Tokens = Tokens.slice(findTokenAt(Loc) - Tokens.begin());
}
ArrayRef<RawSyntaxInfo> dropTokenAt(SourceLoc Loc) const {
return Tokens.take_front(findTokenAt(Loc) - Tokens.begin());
}
// Check if the pending syntax is a token syntax in the given kind.
bool checkTokenFromBack(tok Kind, ArrayRef<RawSyntaxInfo> UsedTokens,
unsigned OffsetFromBack = 0) {
if (UsedTokens.size() - 1 < OffsetFromBack)
return false;
auto Back = UsedTokens[UsedTokens.size() - 1 - OffsetFromBack].
makeSyntax<Syntax>().getAs<TokenSyntax>();
return Back.hasValue() && Back->getTokenKind() == Kind;
}
};
static void addNodeToResults(std::vector<RawSyntaxInfo> &Results,
std::vector<RawSyntaxInfo> &ImplicitNodes,
RawSyntaxInfo Info) {
// Add implicit nodes before adding the explicit nodes they attach to.
assert(!Info.isImplicit());
auto StartSize = Results.size();
// Find all implicit nodes where the attach-to location is the start position
// of this non-implicit nodes.
Results.insert(Results.end(),
std::find_if(ImplicitNodes.begin(), ImplicitNodes.end(),
[&](const RawSyntaxInfo &Imp) {
return Imp.BeforeLoc == Info.getStartLoc();
}),
ImplicitNodes.end());
// If any implicit nodes are inserted to results, we should clear the buffer
// to avoid re-inserting them.
if (StartSize != Results.size()) {
ImplicitNodes.clear();
}
// Add the non-implicit node.
Results.emplace_back(Info);
}
std::vector<RawSyntaxInfo>
SyntaxParsingContext::ContextInfo::collectAllSyntax(SourceLoc EndLoc) {
std::vector<RawSyntaxInfo> Results;
std::vector<RawSyntaxInfo> ImplicitNodes;
auto CurSyntax = PendingSyntax.begin();
for (auto It = Tokens.begin(); It->getStartLoc() != EndLoc;) {
auto Tok = *It;
if (CurSyntax == PendingSyntax.end()) {
// If no remaining syntax nodes, add the token.
addNodeToResults(Results, ImplicitNodes, Tok);
It ++;
} else if (CurSyntax->isImplicit()) {
ImplicitNodes.emplace_back(*CurSyntax);
// Skip implicit syntax node.
CurSyntax ++;
} else if (CurSyntax->getStartLoc() == Tok.getStartLoc()) {
// Prefer syntax nodes to tokens.
addNodeToResults(Results, ImplicitNodes, *CurSyntax);
while(It->getEndLoc() != CurSyntax->getEndLoc()) It++;
assert(It < Tokens.end() && It->getEndLoc() == CurSyntax->getEndLoc());
It ++;
CurSyntax ++;
} else {
// We have to add token in this case since the next syntax node has not
// started.
assert(Tok.getStartLoc().getOpaquePointerValue() <
CurSyntax->getStartLoc().getOpaquePointerValue());
addNodeToResults(Results, ImplicitNodes, Tok);
It ++;
}
}
// Add the remaining syntax nodes.
for (;CurSyntax != PendingSyntax.end(); CurSyntax ++) {
Results.emplace_back(*CurSyntax);
}
return Results;
}
void SyntaxParsingContext::ContextInfo::
createPartiallyFromBack(SyntaxKind Kind, ArrayRef<RawSyntaxInfo> NodesToUse,
unsigned N) {
auto Size = NodesToUse.size();
assert(N && Size >= N);
auto Parts = llvm::makeArrayRef(NodesToUse).slice(Size - N);
// Count the parts from the pending syntax list.
unsigned UsedPending = std::accumulate(Parts.begin(), Parts.end(), 0,
[](unsigned Count, RawSyntaxInfo Info) {
return Count += Info.RawNode->isToken() ? 0 : 1;
});
// Remove all pending syntax ndoes that we used to create the new node.
for (unsigned I = 0; I < UsedPending; I ++)
PendingSyntax.pop_back();
// Add result to the pending syntax list.
addPendingSyntax(createSyntaxAs(Parts, Kind));
}
void SyntaxParsingContext::ContextInfo::
createWhole(SyntaxKind Kind, ArrayRef<RawSyntaxInfo> NodesToUse) {
auto Result = createSyntaxAs(NodesToUse, Kind);
PendingSyntax.clear();
addPendingSyntax(Result);
}
SyntaxParsingContext::
SyntaxParsingContext(SourceFile &SF, unsigned BufferID, Token &Tok):
ContextData(*new ContextInfo(SF, BufferID)),
Tok(Tok) {}
SyntaxParsingContext::SyntaxParsingContext(SyntaxParsingContext &Another):
ContextData(*new ContextInfo(Another.ContextData.allTokens(),
Another.ContextData.Enabled)), Tok(Another.Tok) {}
SyntaxParsingContext::~SyntaxParsingContext() { delete &ContextData; }
void SyntaxParsingContext::disable() { ContextData.Enabled = false; }
SyntaxParsingContextRoot::~SyntaxParsingContextRoot() {
if (!ContextData.Enabled)
return;
std::vector<DeclSyntax> AllTopLevel;
if (File.hasSyntaxRoot()) {
for (auto It: File.getSyntaxRoot().getTopLevelDecls()) {
AllTopLevel.push_back(It);
}
}
for (auto Info: ContextData.getPendingSyntax()) {
assert(Info.RawNode->Kind == SyntaxKind::StmtList);
AllTopLevel.push_back(SyntaxFactory::makeTopLevelCodeDecl(
Info.makeSyntax<StmtListSyntax>()));
}
File.setSyntaxRoot(
SyntaxFactory::makeSourceFile(SyntaxFactory::makeDeclList(AllTopLevel),
// The last node must be eof.
ContextData.allTokens().back().makeSyntax<TokenSyntax>()));
}
SyntaxParsingContextRoot &SyntaxParsingContextChild::getRoot() {
for (SyntaxParsingContext *Root = getParent(); ;
Root = static_cast<SyntaxParsingContextChild*>(Root)->getParent()){
if (Root->getKind() == SyntaxParsingContextKind::Root)
return *static_cast<SyntaxParsingContextRoot*>(Root);
}
llvm_unreachable("can not find root");
}
SyntaxParsingContextChild::
SyntaxParsingContextChild(SyntaxParsingContext *&ContextHolder,
Optional<SyntaxContextKind> ContextKind, Optional<SyntaxKind> KnownSyntax):
SyntaxParsingContext(*ContextHolder), Parent(ContextHolder),
ContextHolder(ContextHolder), ContextKind(ContextKind),
KnownSyntax(KnownSyntax) {
ContextHolder = this;
if (ContextData.Enabled)
ContextData.setContextStart(Tok.getLoc());
}
void SyntaxParsingContextChild::setSyntaxKind(SyntaxKind SKind) {
assert(!KnownSyntax.hasValue() && "reset");
KnownSyntax = SKind;
ContextKind = None;
}
void SyntaxParsingContextChild::setContextKind(SyntaxContextKind CKind) {
assert(!ContextKind.hasValue() && "reset");
ContextKind = CKind;
KnownSyntax = None;
}
SyntaxParsingContextChild::
SyntaxParsingContextChild(SyntaxParsingContext *&ContextHolder, bool Disable):
SyntaxParsingContextChild(ContextHolder, None, None) {
if (Disable)
disable();
}
void SyntaxParsingContextChild::makeNode(SyntaxKind Kind, SourceLoc EndLoc) {
assert(isTopOfContextStack());
if (!ContextData.Enabled)
return;
auto AllNodes = ContextData.collectAllSyntax(EndLoc);
// Create syntax nodes according to the given kind.
switch (Kind) {
case SyntaxKind::FloatLiteralExpr:
case SyntaxKind::IntegerLiteralExpr: {
// Integer may include the signs before the digits, so check if the sign
// exists and create.
ContextData.createPartiallyFromBack(Kind, AllNodes, ContextData.
checkTokenFromBack(tok::oper_prefix, AllNodes, 1) ? 2 : 1);
break;
}
case SyntaxKind::TernaryExpr:
case SyntaxKind::StringLiteralExpr: {
auto Pair = SyntaxFactory::countChildren(Kind);
assert(Pair.first == Pair.second);
ContextData.createPartiallyFromBack(Kind, AllNodes, Pair.first);
break;
}
default:
llvm_unreachable("Unrecognized node kind.");
}
}
void SyntaxParsingContextChild::makeNodeWhole(SyntaxKind Kind) {
assert(ContextData.Enabled);
assert(isTopOfContextStack());
auto EndLoc = Tok.getLoc();
auto AllNodes = ContextData.collectAllSyntax(EndLoc);
switch (Kind) {
case SyntaxKind::BooleanLiteralExpr:
case SyntaxKind::NilLiteralExpr:
case SyntaxKind::DiscardAssignmentExpr:
case SyntaxKind::IdentifierExpr:
case SyntaxKind::DictionaryExpr:
case SyntaxKind::ArrayExpr:
case SyntaxKind::DictionaryElement:
case SyntaxKind::ArrayElement:
case SyntaxKind::FunctionCallArgument:
case SyntaxKind::CodeBlock: {
ContextData.createWhole(Kind, AllNodes);
break;
}
case SyntaxKind::DictionaryElementList:
case SyntaxKind::ArrayElementList:
case SyntaxKind::StmtList:
case SyntaxKind::FunctionCallArgumentList: {
if (AllNodes.empty()) {
// Create an empty argument list if no arguments are in the context.
RawSyntaxInfo Empty(SyntaxFactory::
makeBlankCollectionSyntax(Kind).getRaw());
Empty.setBeforeLoc(EndLoc);
ContextData.addPendingSyntax(Empty);
} else {
ContextData.createWhole(Kind, AllNodes);
}
break;
}
default:
llvm_unreachable("Unrecognized node kind.");
}
}
void RawSyntaxInfo::brigeWithContext(SyntaxContextKind Kind) {
switch (Kind) {
case SyntaxContextKind::Stmt: {
if (RawNode->isDecl()) {
// Wrap a declaration with a declaration statement
RawNode = SyntaxFactory::createSyntax(SyntaxKind::DeclarationStmt,
{ makeSyntax<Syntax>() })->getRaw();
} else if (RawNode->isExpr()) {
// Wrap an expression with an expression statement
RawNode = SyntaxFactory::createSyntax(SyntaxKind::ExpressionStmt,
{ makeSyntax<Syntax>() })->getRaw();
} else if (RawNode->isToken()) {
// Wrap a standalone token withn an expression statement
RawNode = SyntaxFactory::createSyntax(SyntaxKind::ExpressionStmt,
makeUnknownSyntax(SyntaxKind::UnknownExpr,
{make<Syntax>(RawNode)}))->getRaw();
}
assert(RawNode->isStmt());
break;
}
case SyntaxContextKind::Decl: {
if (!RawNode->isDecl()) {
RawNode = makeUnknownSyntax(SyntaxKind::UnknownDecl,
{make<Syntax>(RawNode)}).getRaw();
}
assert(RawNode->isDecl());
break;
}
case SyntaxContextKind::Expr:
if (!RawNode->isExpr()) {
RawNode = makeUnknownSyntax(SyntaxKind::UnknownExpr,
{make<Syntax>(RawNode)}).getRaw();
}
assert(RawNode->isExpr());
break;
}
}
void SyntaxParsingContextChild::finalize() {
assert(isTopOfContextStack());
SWIFT_DEFER {
// Reset the context holder to be Parent.
ContextHolder = Parent;
};
if (!ContextData.Enabled)
return;
assert(ContextKind.hasValue() != KnownSyntax.hasValue());
SourceLoc EndLoc = Tok.getLoc();
if (KnownSyntax) {
// If the entire context should be created to a known syntax kind, create
// all pending syntax nodes into that node.
makeNodeWhole(*KnownSyntax);
assert(ContextData.getPendingSyntax().size() == 1);
Parent->ContextData.addPendingSyntax(ContextData.getPendingSyntax().front());
return;
}
auto AllNodes = ContextData.collectAllSyntax(EndLoc);
RC<RawSyntax> FinalResult;
if (AllNodes.empty())
return;
// Make sure we used all tokens.
assert(AllNodes.front().getStartLoc() == ContextData.getContextStartLoc());
if (AllNodes.size() == 1) {
// If we have only one syntax node remaining, we are done.
auto Result = AllNodes.front();
// Bridge the syntax node to the expected context kind.
Result.brigeWithContext(*ContextKind);
Parent->ContextData.addPendingSyntax(Result);
return;
}
llvm::SmallVector<Syntax, 8> Scratch;
auto SyntaxNodes = getSyntaxNodes(AllNodes, Scratch);
SourceLoc Start = AllNodes.front().getStartLoc();
SourceLoc End = AllNodes.back().getEndLoc();
SyntaxKind UnknownKind;
switch (*ContextKind) {
case SyntaxContextKind::Expr:
UnknownKind = SyntaxKind::UnknownExpr;
break;
case SyntaxContextKind::Decl:
UnknownKind = SyntaxKind::UnknownDecl;
break;
case SyntaxContextKind::Stmt:
UnknownKind = SyntaxKind::UnknownStmt;
break;
}
// Create an unknown node and give it to the parent context.
Parent->ContextData.addPendingSyntax({SourceRange(Start, End),
makeUnknownSyntax(UnknownKind, SyntaxNodes).getRaw()});
}
SyntaxParsingContextChild::~SyntaxParsingContextChild() {
if (isTopOfContextStack())
finalize();
}