Skip to content

Commit 6beee6a

Browse files
committed
Code completion: implement delayed parsing and code completion for
TopLevelCodeDecls Swift SVN r6638
1 parent 497ec93 commit 6beee6a

File tree

5 files changed

+140
-3
lines changed

5 files changed

+140
-3
lines changed

Diff for: include/swift/Parse/Parser.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -392,12 +392,17 @@ class Parser {
392392
bool parseList(tok RightK, SourceLoc LeftLoc, SourceLoc &RightLoc,
393393
tok SeparatorK, bool OptionalSep, Diag<> ErrorDiag,
394394
std::function<bool()> callback);
395-
395+
396+
void consumeTopLevelDecl(TopLevelCodeDecl *TLCD,
397+
ParserPosition BeginParserPosition);
398+
396399
void parseBraceItems(SmallVectorImpl<ExprStmtOrDecl> &Decls,
397400
bool IsTopLevel,
398401
BraceItemListKind Kind = BraceItemListKind::Brace);
399402
NullablePtr<BraceStmt> parseBraceItemList(Diag<> ID);
400403

404+
void parseTopLevelCodeDeclDelayed();
405+
401406
//===--------------------------------------------------------------------===//
402407
// Decl Parsing
403408
static bool isStartOfDecl(const Token &Tok, const Token &Tok2);

Diff for: include/swift/Parse/PersistentParserState.h

+37
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
#include "llvm/ADT/DenseMap.h"
2323

2424
namespace swift {
25+
class Decl;
2526
class FuncExpr;
27+
class TopLevelCodeDecl;
2628

2729
/// \brief Parser state persistent across multiple parses.
2830
class PersistentParserState {
@@ -50,21 +52,56 @@ class PersistentParserState {
5052
{}
5153
};
5254

55+
class DelayedDeclState {
56+
friend class PersistentParserState;
57+
friend class Parser;
58+
Decl *D;
59+
ParserPos BodyPos;
60+
SourceLoc BodyEnd;
61+
SavedScope Scope;
62+
63+
SavedScope takeScope() {
64+
return std::move(Scope);
65+
}
66+
67+
public:
68+
DelayedDeclState(Decl *D, SourceRange BodyRange, SourceLoc PreviousLoc,
69+
SavedScope &&Scope)
70+
: D(D), BodyPos{BodyRange.Start, PreviousLoc},
71+
BodyEnd(BodyRange.End), Scope(std::move(Scope))
72+
{}
73+
};
74+
5375
private:
5476
ScopeInfo ScopeInfo;
5577
typedef llvm::DenseMap<FuncExpr *, std::unique_ptr<FunctionBodyState>>
5678
DelayedBodiesTy;
5779
DelayedBodiesTy DelayedBodies;
80+
5881
/// \brief Parser sets this if it stopped parsing before the buffer ended.
5982
ParserPos MarkedPos;
6083

84+
std::unique_ptr<DelayedDeclState> CodeCompletionDelayedDeclState;
85+
6186
public:
6287
swift::ScopeInfo &getScopeInfo() { return ScopeInfo; }
6388

6489
void delayFunctionBodyParsing(FuncExpr *FE, SourceRange BodyRange,
6590
SourceLoc PreviousLoc);
6691
std::unique_ptr<FunctionBodyState> takeBodyState(FuncExpr *FE);
6792

93+
void delayTopLevelCodeDecl(TopLevelCodeDecl *TLCD, SourceRange BodyRange,
94+
SourceLoc PreviousLoc);
95+
bool hasDelayedDecl() {
96+
return CodeCompletionDelayedDeclState.get() != nullptr;
97+
}
98+
SourceLoc getDelayedDeclLoc() {
99+
return CodeCompletionDelayedDeclState->BodyPos.Loc;
100+
}
101+
std::unique_ptr<DelayedDeclState> takeDelayedDeclState() {
102+
return std::move(CodeCompletionDelayedDeclState);
103+
}
104+
68105
void markParserPosition(SourceLoc Loc, SourceLoc PrevLoc) {
69106
MarkedPos = {Loc, PrevLoc};
70107
}

Diff for: lib/Parse/ParseStmt.cpp

+58-2
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,16 @@ static bool isTerminatorForBraceItemListKind(const Token &Tok,
132132
}
133133
}
134134

135+
void Parser::consumeTopLevelDecl(TopLevelCodeDecl *TLCD,
136+
ParserPosition BeginParserPosition) {
137+
backtrackToPosition(BeginParserPosition);
138+
SourceLoc BeginLoc = Tok.getLoc();
139+
skipUntilDeclStmtRBrace();
140+
SourceLoc EndLoc = Tok.getLoc();
141+
State->delayTopLevelCodeDecl(TLCD, { BeginLoc, EndLoc },
142+
BeginParserPosition.PreviousLoc);
143+
}
144+
135145
/// brace-item:
136146
/// decl
137147
/// expr
@@ -194,8 +204,19 @@ void Parser::parseBraceItems(SmallVectorImpl<ExprStmtOrDecl> &Entries,
194204
auto *TLCD = new (Context) TopLevelCodeDecl(CurDeclContext);
195205
ContextChange CC(*this, TLCD);
196206
SourceLoc StartLoc = Tok.getLoc();
197-
198-
if (parseExprOrStmt(Result)) {
207+
208+
ParserPosition BeginParserPosition;
209+
if (isCodeCompletionFirstPass())
210+
BeginParserPosition = getParserPosition();
211+
212+
bool FailedToParse = parseExprOrStmt(Result);
213+
214+
if (Tok.is(tok::code_complete)) {
215+
consumeTopLevelDecl(TLCD, BeginParserPosition);
216+
return;
217+
}
218+
219+
if (FailedToParse) {
199220
NeedParseErrorRecovery = true;
200221
} else {
201222
auto Brace = BraceStmt::create(Context, StartLoc, Result, Tok.getLoc());
@@ -244,6 +265,41 @@ void Parser::parseBraceItems(SmallVectorImpl<ExprStmtOrDecl> &Entries,
244265
}
245266
}
246267

268+
void Parser::parseTopLevelCodeDeclDelayed() {
269+
auto DelayedState = State->takeDelayedDeclState();
270+
assert(DelayedState.get() && "should have delayed state");
271+
272+
auto *TLCD = dyn_cast<TopLevelCodeDecl>(DelayedState->D);
273+
assert(!TLCD->getBody() && "should not have a parsed body");
274+
275+
auto BeginParserPosition = getParserPosition(DelayedState->BodyPos);
276+
auto EndLexerState = L->getStateForEndOfTokenLoc(DelayedState->BodyEnd);
277+
278+
// ParserPositionRAII needs a primed parser to restore to.
279+
if (Tok.is(tok::NUM_TOKENS))
280+
consumeToken();
281+
282+
// Ensure that we restore the parser state at exit.
283+
ParserPositionRAII PPR(*this);
284+
285+
// Create a lexer that can not go past the end state.
286+
Lexer LocalLex(*L, BeginParserPosition.LS, EndLexerState, SourceMgr, &Diags,
287+
nullptr /*not SIL*/);
288+
289+
// Temporarily swap out the parser's current lexer with our new one.
290+
llvm::SaveAndRestore<Lexer *> T(L, &LocalLex);
291+
292+
// Rewind to '{' of the function body.
293+
restoreParserPosition(BeginParserPosition);
294+
295+
// Re-enter the lexical scope.
296+
Scope S(this, DelayedState->takeScope());
297+
ContextChange CC(*this, TLCD);
298+
299+
ExprStmtOrDecl Result;
300+
parseExprOrStmt(Result);
301+
}
302+
247303
/// Recover from a 'case' or 'default' outside of a 'switch' by consuming up to
248304
/// the next ':'.
249305
static NullablePtr<Stmt> recoverFromInvalidCase(Parser &P) {

Diff for: lib/Parse/Parser.cpp

+28
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,30 @@ class ParseDelayedFunctionBodies : public ASTWalker {
9999
TheParser.parseDeclFuncBodyDelayed(FD);
100100
}
101101
};
102+
103+
void
104+
parseDelayedTopLevelDecl(TranslationUnit *TU,
105+
PersistentParserState &ParserState,
106+
CodeCompletionCallbacksFactory *CodeCompletionFactory,
107+
unsigned CodeCompletionOffset) {
108+
assert(CodeCompletionFactory &&
109+
"delayed parsing of decls only makes sense for code completion");
110+
111+
if (!ParserState.hasDelayedDecl())
112+
return;
113+
114+
int BufferID = TU->Ctx.SourceMgr
115+
.FindBufferContainingLoc(ParserState.getDelayedDeclLoc().Value);
116+
Parser TheParser(BufferID, TU,
117+
TU->Kind == TranslationUnit::Main ||
118+
TU->Kind == TranslationUnit::REPL, nullptr, &ParserState);
119+
120+
std::unique_ptr<CodeCompletionCallbacks> CodeCompletion(
121+
CodeCompletionFactory->createCodeCompletionCallbacks(TheParser));
122+
TheParser.setCodeCompletion(CodeCompletionOffset);
123+
TheParser.setCodeCompletionCallbacks(CodeCompletion.get());
124+
TheParser.parseTopLevelCodeDeclDelayed();
125+
}
102126
} // unnamed namespace
103127

104128
/// parseIntoTranslationUnit - Entrypoint for the parser.
@@ -138,6 +162,10 @@ void swift::performDelayedParsing(
138162
for (Decl *D : TU->Decls) {
139163
D->walk(Walker);
140164
}
165+
166+
if (CodeCompletionFactory)
167+
parseDelayedTopLevelDecl(TU, PersistentState, CodeCompletionFactory,
168+
CodeCompletionOffset);
141169
}
142170

143171
std::vector<Token> swift::tokenize(llvm::SourceMgr &SM, unsigned BufferID,

Diff for: lib/Parse/PersistentParserState.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
//
1515
//===----------------------------------------------------------------------===//
1616

17+
#include "swift/AST/Decl.h"
1718
#include "swift/AST/Expr.h"
1819
#include "swift/Parse/PersistentParserState.h"
1920

@@ -39,3 +40,13 @@ PersistentParserState::takeBodyState(FuncExpr *FE) {
3940
DelayedBodies.erase(I);
4041
return State;
4142
}
43+
44+
void PersistentParserState::delayTopLevelCodeDecl(TopLevelCodeDecl *TLCD,
45+
SourceRange BodyRange,
46+
SourceLoc PreviousLoc) {
47+
assert(!CodeCompletionDelayedDeclState.get() &&
48+
"only one decl can be delayed for code completion");
49+
CodeCompletionDelayedDeclState.reset(new DelayedDeclState(
50+
TLCD, BodyRange, PreviousLoc, ScopeInfo.saveCurrentScope()));
51+
}
52+

0 commit comments

Comments
 (0)