REPL: pass all unprocessed lines to code completion

This enables us to do code completion in function bodies and resolve local
variables.


Swift SVN r7118
This commit is contained in:
Dmitri Hrybenko
2013-08-10 01:18:43 +00:00
parent ca5351e4b6
commit 0761a2ebd7
2 changed files with 44 additions and 19 deletions

View File

@@ -0,0 +1,15 @@
// RUN: %swift-ide-test -repl-code-completion -source-filename %s | FileCheck %s
// Make sure we partially type check the function body even if function body is
// missing the right brace.
// Don't add any tests at the end of the file!
//
// CHECK: Begin completions
// CHECK-DAG: SwiftDecl: a()[#Void#]{{$}}
// CHECK: End completions
struct FooStruct {
func a() {}
}
func f() {
var foo = FooStruct()
foo.

View File

@@ -18,6 +18,7 @@
#include "Immediate.h" #include "Immediate.h"
#include "Frontend.h" #include "Frontend.h"
#include "swift/Subsystems.h" #include "swift/Subsystems.h"
#include "swift/Basic/LLVM.h"
#include "swift/IRGen/Options.h" #include "swift/IRGen/Options.h"
#include "swift/Parse/Lexer.h" #include "swift/Parse/Lexer.h"
#include "swift/AST/ASTContext.h" #include "swift/AST/ASTContext.h"
@@ -419,6 +420,9 @@ class REPLInput {
llvm::SmallVector<wchar_t, 80> PromptString; llvm::SmallVector<wchar_t, 80> PromptString;
/// A buffer for all lines that the user entered, but we have not parsed yet.
llvm::SmallString<128> CurrentLines;
public: public:
REPLEnvironment &Env; REPLEnvironment &Env;
bool Autoindent; bool Autoindent;
@@ -490,14 +494,14 @@ public:
TranslationUnit *getTU(); TranslationUnit *getTU();
REPLInputKind getREPLInput(llvm::SmallVectorImpl<char> &Line) { REPLInputKind getREPLInput(SmallVectorImpl<char> &Result) {
int BraceCount = 0; int BraceCount = 0;
bool HadLineContinuation = false; bool HadLineContinuation = false;
bool UnfinishedInfixExpr = false; bool UnfinishedInfixExpr = false;
unsigned CurChunkLines = 0; unsigned CurChunkLines = 0;
Line.clear(); CurrentLines.clear();
// Reset color before showing the prompt. // Reset color before showing the prompt.
if (ShowColors) if (ShowColors)
llvm::outs().resetColor(); llvm::outs().resetColor();
@@ -510,7 +514,7 @@ public:
PromptedForLine = false; PromptedForLine = false;
Outdented = false; Outdented = false;
int LineCount; int LineCount;
size_t LineStart = Line.size(); size_t LineStart = CurrentLines.size();
const wchar_t* WLine = el_wgets(e, &LineCount); const wchar_t* WLine = el_wgets(e, &LineCount);
if (!WLine) { if (!WLine) {
// End-of-file. // End-of-file.
@@ -521,15 +525,17 @@ public:
if (Autoindent) { if (Autoindent) {
size_t indent = PromptContinuationLevel*2; size_t indent = PromptContinuationLevel*2;
Line.append(indent, ' '); CurrentLines.append(indent, ' ');
} }
convertToUTF8(llvm::makeArrayRef(WLine, WLine + wcslen(WLine)), Line); convertToUTF8(llvm::makeArrayRef(WLine, WLine + wcslen(WLine)),
CurrentLines);
// Special-case backslash for line continuations in the REPL. // Special-case backslash for line continuations in the REPL.
if (Line.size() > 2 && Line.end()[-1] == '\n' && Line.end()[-2] == '\\') { if (CurrentLines.size() > 2 &&
CurrentLines.end()[-1] == '\n' && CurrentLines.end()[-2] == '\\') {
HadLineContinuation = true; HadLineContinuation = true;
Line.erase(Line.end() - 2); CurrentLines.erase(CurrentLines.end() - 2);
} else { } else {
HadLineContinuation = false; HadLineContinuation = false;
} }
@@ -544,12 +550,12 @@ public:
// If we detect a line starting with a colon, treat it as a special // If we detect a line starting with a colon, treat it as a special
// REPL escape. // REPL escape.
char const *s = Line.data() + LineStart; char const *s = CurrentLines.data() + LineStart;
char const *p = s; char const *p = s;
while (p < Line.end() && isspace(*p)) { while (p < CurrentLines.end() && isspace(*p)) {
++p; ++p;
} }
if (p == Line.end()) { if (p == CurrentLines.end()) {
if (BraceCount != 0 || UnfinishedInfixExpr) continue; if (BraceCount != 0 || UnfinishedInfixExpr) continue;
return REPLInputKind::Empty; return REPLInputKind::Empty;
} }
@@ -566,7 +572,7 @@ public:
// If we detect unbalanced braces, keep reading before // If we detect unbalanced braces, keep reading before
// we start parsing. // we start parsing.
while (p < Line.end()) { while (p < CurrentLines.end()) {
if (*p == '{' || *p == '(' || *p == '[') if (*p == '{' || *p == '(' || *p == '[')
++BraceCount; ++BraceCount;
else if (*p == '}' || *p == ')' || *p == ']') else if (*p == '}' || *p == ')' || *p == ']')
@@ -581,10 +587,13 @@ public:
UnfinishedInfixExpr = true; UnfinishedInfixExpr = true;
} }
} while (BraceCount > 0 || HadLineContinuation || UnfinishedInfixExpr); } while (BraceCount > 0 || HadLineContinuation || UnfinishedInfixExpr);
Result.clear();
Result.append(CurrentLines.begin(), CurrentLines.end());
// The lexer likes null-terminated data. // The lexer likes null-terminated data.
Line.push_back('\0'); Result.push_back('\0');
Line.pop_back(); Result.pop_back();
// Colorize the response output. // Colorize the response output.
if (ShowColors) if (ShowColors)
@@ -838,12 +847,13 @@ private:
unsigned char onComplete(int ch) { unsigned char onComplete(int ch) {
LineInfoW const *line = el_wline(e); LineInfoW const *line = el_wline(e);
llvm::ArrayRef<wchar_t> wprefix(line->buffer, line->cursor - line->buffer); llvm::ArrayRef<wchar_t> wprefix(line->buffer, line->cursor - line->buffer);
llvm::SmallString<16> prefix; llvm::SmallString<16> Prefix;
convertToUTF8(wprefix, prefix); Prefix.assign(CurrentLines);
convertToUTF8(wprefix, Prefix);
if (!completions) { if (!completions) {
// If we aren't currently working with a completion set, generate one. // If we aren't currently working with a completion set, generate one.
completions.populate(getTU(), prefix); completions.populate(getTU(), Prefix);
// Display the common root of the found completions and beep unless we // Display the common root of the found completions and beep unless we
// found a unique one. // found a unique one.
insertStringRef(completions.getRoot()); insertStringRef(completions.getRoot());