Tons of hacking, but not necessarily tons of progress
This commit is contained in:
parent
267dbab208
commit
814dcbd26a
19
README.md
19
README.md
|
@ -1,8 +1,15 @@
|
||||||
DCD
|
#Overview
|
||||||
===
|
The D Completion Daemon is an auto-complete program for the D programming language.
|
||||||
|
|
||||||
The D Completion Daemon is an auto-complete program for the D programming language
|
#Status
|
||||||
|
* Working:
|
||||||
|
* Autocomplete class, struct, interface, and enum members if the class, struct, or
|
||||||
|
enum was declared in the current file.
|
||||||
|
* Autocompletion of properties of built-in types such as int, float, double, etc.
|
||||||
|
* Not working:
|
||||||
|
* Everything else
|
||||||
|
|
||||||
Or at least it will be once I write it.
|
#Setup
|
||||||
|
Don't. This code is not ready for you to use yet. If you're going to ignore this
|
||||||
Be sure to run ```git submodule update --init``` after cloning this repository.
|
warning, be sure to run ```git submodule update --init``` after cloning this
|
||||||
|
repository to grab the MessagePack library.
|
||||||
|
|
118
actypes.d
118
actypes.d
|
@ -23,26 +23,99 @@ import std.algorithm;
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
import messages;
|
import messages;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Autocompletion symbol
|
||||||
|
*/
|
||||||
class ACSymbol
|
class ACSymbol
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ACSymbol[] parts;
|
|
||||||
string name;
|
this()
|
||||||
CompletionKind kind;
|
{
|
||||||
Type[string] templateParameters;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this(string name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
this(string name, CompletionKind kind)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
this.kind = kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
this(string name, CompletionKind kind, ACSymbol resolvedType)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
this.kind = kind;
|
||||||
|
this.resolvedType = resolvedType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Symbols that compose this symbol, such as enum members, class variables,
|
||||||
|
* methods, etc.
|
||||||
|
*/
|
||||||
|
ACSymbol[] parts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Symbol's name
|
||||||
|
*/
|
||||||
|
string name;
|
||||||
|
|
||||||
|
size_t location;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The kind of symbol
|
||||||
|
*/
|
||||||
|
CompletionKind kind;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The return type if this is a function, or the element type if this is an
|
||||||
|
* array or associative array, or the variable type if this is a variable.
|
||||||
|
* This field is null if this symbol is a class
|
||||||
|
*/
|
||||||
|
Type type;
|
||||||
|
|
||||||
|
ACSymbol resolvedType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds symbol parts by name
|
||||||
|
*/
|
||||||
|
ACSymbol getPartByName(string name)
|
||||||
|
{
|
||||||
|
foreach (part; parts)
|
||||||
|
{
|
||||||
|
if (part.name == name)
|
||||||
|
return part;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope such as a block statement, struct body, etc.
|
||||||
|
*/
|
||||||
class Scope
|
class Scope
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Params:
|
||||||
|
* start = the index of the opening brace
|
||||||
|
* end = the index of the closing brace
|
||||||
|
*/
|
||||||
this(size_t start, size_t end)
|
this(size_t start, size_t end)
|
||||||
{
|
{
|
||||||
this.start = start;
|
this.start = start;
|
||||||
this.end = end;
|
this.end = end;
|
||||||
}
|
}
|
||||||
|
|
||||||
const(ACSymbol) findSymbolInCurrentScope(size_t cursorPosition, string name) const
|
/**
|
||||||
|
* Finds the scope containing the cursor position, then searches for a
|
||||||
|
* symbol with the given name.
|
||||||
|
*/
|
||||||
|
ACSymbol findSymbolInCurrentScope(size_t cursorPosition, string name)
|
||||||
{
|
{
|
||||||
auto s = findCurrentScope(cursorPosition);
|
auto s = findCurrentScope(cursorPosition);
|
||||||
if (s is null)
|
if (s is null)
|
||||||
|
@ -55,11 +128,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the innermost Scope that contains the given cursor position.
|
* Returns: the innermost Scope that contains the given cursor position.
|
||||||
*/
|
*/
|
||||||
const(Scope) findCurrentScope(size_t cursorPosition) const
|
Scope findCurrentScope(size_t cursorPosition)
|
||||||
{
|
{
|
||||||
if (cursorPosition < start || cursorPosition > end)
|
if (start != size_t.max && (cursorPosition < start || cursorPosition > end))
|
||||||
return null;
|
return null;
|
||||||
foreach (sc; children)
|
foreach (sc; children)
|
||||||
{
|
{
|
||||||
|
@ -72,7 +145,11 @@ public:
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
const(ACSymbol) findSymbolInScope(string name) const
|
/**
|
||||||
|
* Finds a symbol with the given name in this scope or one of its parent
|
||||||
|
* scopes.
|
||||||
|
*/
|
||||||
|
ACSymbol findSymbolInScope(string name)
|
||||||
{
|
{
|
||||||
foreach (symbol; symbols)
|
foreach (symbol; symbols)
|
||||||
{
|
{
|
||||||
|
@ -84,9 +161,28 @@ public:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t start;
|
/**
|
||||||
size_t end;
|
* Index of the opening brace
|
||||||
|
*/
|
||||||
|
size_t start = size_t.max;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index of the closing brace
|
||||||
|
*/
|
||||||
|
size_t end = size_t.max;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Symbols contained in this scope
|
||||||
|
*/
|
||||||
ACSymbol[] symbols;
|
ACSymbol[] symbols;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parent scope
|
||||||
|
*/
|
||||||
Scope parent;
|
Scope parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Child scopes
|
||||||
|
*/
|
||||||
Scope[] children;
|
Scope[] children;
|
||||||
}
|
}
|
||||||
|
|
130
acvisitor.d
130
acvisitor.d
|
@ -31,21 +31,54 @@ class AutoCompleteVisitor : ASTVisitor
|
||||||
{
|
{
|
||||||
alias ASTVisitor.visit visit;
|
alias ASTVisitor.visit visit;
|
||||||
|
|
||||||
override void visit(EnumDeclaration enumDec)
|
override void visit(StructDeclaration dec)
|
||||||
{
|
{
|
||||||
auto symbol = new ACSymbol;
|
auto symbol = new ACSymbol;
|
||||||
symbol.name = enumDec.name.value;
|
symbol.name = dec.name.value;
|
||||||
|
symbol.kind = CompletionKind.structName;
|
||||||
|
mixin (visitAndAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(ClassDeclaration dec)
|
||||||
|
{
|
||||||
|
auto symbol = new ACSymbol;
|
||||||
|
symbol.name = dec.name.value;
|
||||||
|
symbol.kind = CompletionKind.className;
|
||||||
|
mixin (visitAndAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(InterfaceDeclaration dec)
|
||||||
|
{
|
||||||
|
auto symbol = new ACSymbol;
|
||||||
|
symbol.name = dec.name.value;
|
||||||
|
symbol.kind = CompletionKind.interfaceName;
|
||||||
|
mixin (visitAndAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(StructBody structBody)
|
||||||
|
{
|
||||||
|
auto s = scope_;
|
||||||
|
scope_ = new Scope(structBody.startLocation, structBody.endLocation);
|
||||||
|
scope_.parent = s;
|
||||||
|
structBody.accept(this);
|
||||||
|
scope_ = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(EnumDeclaration dec)
|
||||||
|
{
|
||||||
|
auto symbol = new ACSymbol;
|
||||||
|
symbol.name = dec.name.value;
|
||||||
symbol.kind = CompletionKind.enumName;
|
symbol.kind = CompletionKind.enumName;
|
||||||
auto p = parentSymbol;
|
mixin (visitAndAdd);
|
||||||
parentSymbol = symbol;
|
}
|
||||||
enumDec.accept(this);
|
|
||||||
parentSymbol = p;
|
override void visit(FunctionDeclaration dec)
|
||||||
writeln("Added ", symbol.name);
|
{
|
||||||
if (parentSymbol is null)
|
writeln("Found function declaration ", dec.name.value);
|
||||||
symbols ~= symbol;
|
auto symbol = new ACSymbol;
|
||||||
else
|
symbol.name = dec.name.value;
|
||||||
parentSymbol.parts ~= symbol;
|
symbol.kind = CompletionKind.functionName;
|
||||||
scope_.symbols ~= symbol;
|
mixin (visitAndAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(EnumMember member)
|
override void visit(EnumMember member)
|
||||||
|
@ -53,28 +86,47 @@ class AutoCompleteVisitor : ASTVisitor
|
||||||
auto s = new ACSymbol;
|
auto s = new ACSymbol;
|
||||||
s.kind = CompletionKind.enumMember;
|
s.kind = CompletionKind.enumMember;
|
||||||
s.name = member.name.value;
|
s.name = member.name.value;
|
||||||
writeln("Added enum member ", s.name);
|
// writeln("Added enum member ", s.name);
|
||||||
if (parentSymbol !is null)
|
if (parentSymbol !is null)
|
||||||
parentSymbol.parts ~= s;
|
parentSymbol.parts ~= s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override void visit(VariableDeclaration dec)
|
||||||
|
{
|
||||||
|
foreach (d; dec.declarators)
|
||||||
|
{
|
||||||
|
writeln("Found variable declaration ", d.name.value);
|
||||||
|
auto symbol = new ACSymbol;
|
||||||
|
symbol.type = dec.type;
|
||||||
|
symbol.name = d.name.value;
|
||||||
|
symbol.kind = CompletionKind.variableName;
|
||||||
|
if (parentSymbol is null)
|
||||||
|
symbols ~= symbol;
|
||||||
|
else
|
||||||
|
parentSymbol.parts ~= symbol;
|
||||||
|
scope_.symbols ~= symbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override void visit(ImportDeclaration dec)
|
override void visit(ImportDeclaration dec)
|
||||||
{
|
{
|
||||||
foreach (singleImport; dec.singleImports)
|
foreach (singleImport; dec.singleImports)
|
||||||
{
|
{
|
||||||
imports ~= flattenIdentifierChain(singleImport.identifierChain);
|
imports ~= convertChainToImportPath(singleImport.identifierChain);
|
||||||
}
|
}
|
||||||
if (dec.importBindings !is null)
|
if (dec.importBindings !is null)
|
||||||
{
|
{
|
||||||
imports ~= flattenIdentifierChain(dec.importBindings.singleImport.identifierChain);
|
imports ~= convertChainToImportPath(dec.importBindings.singleImport.identifierChain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(BlockStatement blockStatement)
|
override void visit(BlockStatement blockStatement)
|
||||||
{
|
{
|
||||||
|
writeln("Processing block statement");
|
||||||
auto s = scope_;
|
auto s = scope_;
|
||||||
scope_ = new Scope(blockStatement.startLocation,
|
scope_ = new Scope(blockStatement.startLocation,
|
||||||
blockStatement.endLocation);
|
blockStatement.endLocation);
|
||||||
|
scope_.parent = s;
|
||||||
blockStatement.accept(this);
|
blockStatement.accept(this);
|
||||||
s.children ~= scope_;
|
s.children ~= scope_;
|
||||||
scope_ = s;
|
scope_ = s;
|
||||||
|
@ -86,7 +138,7 @@ class AutoCompleteVisitor : ASTVisitor
|
||||||
mod.accept(this);
|
mod.accept(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string flattenIdentifierChain(IdentifierChain chain)
|
private static string convertChainToImportPath(IdentifierChain chain)
|
||||||
{
|
{
|
||||||
string rVal;
|
string rVal;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
@ -104,44 +156,28 @@ class AutoCompleteVisitor : ASTVisitor
|
||||||
ACSymbol[] symbols;
|
ACSymbol[] symbols;
|
||||||
ACSymbol parentSymbol;
|
ACSymbol parentSymbol;
|
||||||
Scope scope_;
|
Scope scope_;
|
||||||
string[] imports;
|
string[] imports = ["object"];
|
||||||
|
|
||||||
|
private:
|
||||||
|
static enum string visitAndAdd = q{
|
||||||
|
auto p = parentSymbol;
|
||||||
|
parentSymbol = symbol;
|
||||||
|
dec.accept(this);
|
||||||
|
parentSymbol = p;
|
||||||
|
if (parentSymbol is null)
|
||||||
|
symbols ~= symbol;
|
||||||
|
else
|
||||||
|
parentSymbol.parts ~= symbol;
|
||||||
|
scope_.symbols ~= symbol;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void doesNothing(string, int, int, string) {}
|
void doesNothing(string, int, int, string) {}
|
||||||
|
|
||||||
AutoCompleteVisitor processModule(const(Token)[] tokens)
|
AutoCompleteVisitor processModule(const(Token)[] tokens)
|
||||||
{
|
{
|
||||||
Module mod = parseModule(tokens, "", &doesNothing);
|
Module mod = parseModule(tokens, "", null/*&doesNothing*/);
|
||||||
auto visitor = new AutoCompleteVisitor;
|
auto visitor = new AutoCompleteVisitor;
|
||||||
visitor.visit(mod);
|
visitor.visit(mod);
|
||||||
return visitor;
|
return visitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
string[] getImportedFiles(string[] imports, string[] importPaths)
|
|
||||||
{
|
|
||||||
string[] importedFiles;
|
|
||||||
foreach (imp; imports)
|
|
||||||
{
|
|
||||||
bool found = false;
|
|
||||||
foreach (path; importPaths)
|
|
||||||
{
|
|
||||||
string filePath = path ~ "/" ~ imp;
|
|
||||||
if (filePath.exists())
|
|
||||||
{
|
|
||||||
importedFiles ~= filePath;
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
filePath ~= "i"; // check for x.di if x.d isn't found
|
|
||||||
if (filePath.exists())
|
|
||||||
{
|
|
||||||
importedFiles ~= filePath;
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
writeln("Could not locate ", imp);
|
|
||||||
}
|
|
||||||
return importedFiles;
|
|
||||||
}
|
|
||||||
|
|
272
autocomplete.d
272
autocomplete.d
|
@ -90,6 +90,11 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
|
||||||
{
|
{
|
||||||
switch (beforeTokens[$ - 2].type)
|
switch (beforeTokens[$ - 2].type)
|
||||||
{
|
{
|
||||||
|
case TokenType.stringLiteral:
|
||||||
|
case TokenType.wstringLiteral:
|
||||||
|
case TokenType.dstringLiteral:
|
||||||
|
// TODO
|
||||||
|
break;
|
||||||
case TokenType.int_:
|
case TokenType.int_:
|
||||||
case TokenType.uint_:
|
case TokenType.uint_:
|
||||||
case TokenType.long_:
|
case TokenType.long_:
|
||||||
|
@ -104,13 +109,6 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
|
||||||
case TokenType.ushort_:
|
case TokenType.ushort_:
|
||||||
case TokenType.cent_:
|
case TokenType.cent_:
|
||||||
case TokenType.ucent_:
|
case TokenType.ucent_:
|
||||||
response.completionType = CompletionType.identifiers;
|
|
||||||
for (size_t i = 0; i < integerProperties.length; i++)
|
|
||||||
{
|
|
||||||
response.completions ~= integerProperties[i];
|
|
||||||
response.completionKinds ~= CompletionKind.keyword;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TokenType.float_:
|
case TokenType.float_:
|
||||||
case TokenType.ifloat_:
|
case TokenType.ifloat_:
|
||||||
case TokenType.cfloat_:
|
case TokenType.cfloat_:
|
||||||
|
@ -120,27 +118,11 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
|
||||||
case TokenType.real_:
|
case TokenType.real_:
|
||||||
case TokenType.ireal_:
|
case TokenType.ireal_:
|
||||||
case TokenType.creal_:
|
case TokenType.creal_:
|
||||||
response.completionType = CompletionType.identifiers;
|
|
||||||
for (size_t i = 0; i < floatProperties.length; i++)
|
|
||||||
{
|
|
||||||
response.completions ~= floatProperties[i];
|
|
||||||
response.completionKinds ~= CompletionKind.keyword;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TokenType.stringLiteral:
|
|
||||||
case TokenType.wstringLiteral:
|
|
||||||
case TokenType.dstringLiteral:
|
|
||||||
response.completionType = CompletionType.identifiers;
|
|
||||||
for (size_t i = 0; i < arrayProperties.length; i++)
|
|
||||||
{
|
|
||||||
response.completions ~= arrayProperties[i];
|
|
||||||
response.completionKinds ~= CompletionKind.keyword;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TokenType.identifier:
|
case TokenType.identifier:
|
||||||
case TokenType.rParen:
|
case TokenType.rParen:
|
||||||
case TokenType.rBracket:
|
case TokenType.rBracket:
|
||||||
auto visitor = processModule(tokenArray);
|
auto visitor = processModule(tokenArray);
|
||||||
|
visitor.scope_.symbols ~= builtinSymbols;
|
||||||
auto expression = getExpression(beforeTokens[0..$]);
|
auto expression = getExpression(beforeTokens[0..$]);
|
||||||
response.setCompletions(visitor, expression, request.cursorPosition);
|
response.setCompletions(visitor, expression, request.cursorPosition);
|
||||||
break;
|
break;
|
||||||
|
@ -160,23 +142,116 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCompletions(T)(ref AutocompleteResponse response,
|
void setCompletions(T)(ref AutocompleteResponse response,
|
||||||
ref const AutoCompleteVisitor visitor, T tokens, size_t cursorPosition)
|
AutoCompleteVisitor visitor, T tokens, size_t cursorPosition)
|
||||||
{
|
{
|
||||||
// TODO: Completely hacked together.
|
// TODO: Completely hacked together.
|
||||||
if (tokens[0] != TokenType.identifier) return;
|
writeln("Getting completions for ", map!"a.value"(tokens));
|
||||||
writeln("Getting completions for ", tokens[0].value);
|
ACSymbol symbol = visitor.scope_.findSymbolInCurrentScope(cursorPosition, tokens[0].value);
|
||||||
auto symbol = visitor.scope_.findSymbolInCurrentScope(cursorPosition, tokens[0].value);
|
|
||||||
if (symbol is null)
|
if (symbol is null)
|
||||||
|
{
|
||||||
|
writeln("Could not find declaration of ", tokens[0].value);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeln(symbol.kind);
|
||||||
|
if (symbol.kind == CompletionKind.variableName
|
||||||
|
|| symbol.kind == CompletionKind.memberVariableName)
|
||||||
|
{
|
||||||
|
symbol = resolveType(cursorPosition, symbol, visitor.scope_);
|
||||||
|
}
|
||||||
|
loop: for (size_t i = 1; i < tokens.length; i++)
|
||||||
|
{
|
||||||
|
TokenType open;
|
||||||
|
TokenType close;
|
||||||
|
with (TokenType) switch (tokens[i].type)
|
||||||
|
{
|
||||||
|
case TokenType.int_:
|
||||||
|
case TokenType.uint_:
|
||||||
|
case TokenType.long_:
|
||||||
|
case TokenType.ulong_:
|
||||||
|
case TokenType.char_:
|
||||||
|
case TokenType.wchar_:
|
||||||
|
case TokenType.dchar_:
|
||||||
|
case TokenType.bool_:
|
||||||
|
case TokenType.byte_:
|
||||||
|
case TokenType.ubyte_:
|
||||||
|
case TokenType.short_:
|
||||||
|
case TokenType.ushort_:
|
||||||
|
case TokenType.cent_:
|
||||||
|
case TokenType.ucent_:
|
||||||
|
case TokenType.float_:
|
||||||
|
case TokenType.ifloat_:
|
||||||
|
case TokenType.cfloat_:
|
||||||
|
case TokenType.idouble_:
|
||||||
|
case TokenType.cdouble_:
|
||||||
|
case TokenType.double_:
|
||||||
|
case TokenType.real_:
|
||||||
|
case TokenType.ireal_:
|
||||||
|
case TokenType.creal_:
|
||||||
|
case this_:
|
||||||
|
symbol = symbol.getPartByName(getTokenValue(tokens[i].type));
|
||||||
|
if (symbol is null)
|
||||||
|
break loop;
|
||||||
|
break;
|
||||||
|
case identifier:
|
||||||
|
symbol = symbol.getPartByName(tokens[i].value);
|
||||||
|
if (symbol is null)
|
||||||
|
break loop;
|
||||||
|
break;
|
||||||
|
case lParen:
|
||||||
|
open = TokenType.lParen;
|
||||||
|
close = TokenType.rParen;
|
||||||
|
goto skip;
|
||||||
|
case lBracket:
|
||||||
|
open = TokenType.lBracket;
|
||||||
|
close = TokenType.rBracket;
|
||||||
|
skip:
|
||||||
|
i++;
|
||||||
|
for (int depth = 1; depth > 0 && i < tokens.length; i++)
|
||||||
|
{
|
||||||
|
if (tokens[i].type == open)
|
||||||
|
depth++;
|
||||||
|
else if (tokens[i].type == close)
|
||||||
|
{
|
||||||
|
depth--;
|
||||||
|
if (depth == 0) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case dot:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (s; symbol.parts)
|
foreach (s; symbol.parts)
|
||||||
{
|
{
|
||||||
writeln("Adding ", s.name, " to the completion list");
|
//writeln("Adding ", s.name, " to the completion list");
|
||||||
response.completionKinds ~= s.kind;
|
response.completionKinds ~= s.kind;
|
||||||
response.completions ~= s.name;
|
response.completions ~= s.name;
|
||||||
}
|
}
|
||||||
response.completionType = CompletionType.identifiers;
|
response.completionType = CompletionType.identifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ACSymbol resolveType(size_t cursorPosition, ACSymbol symbol, Scope scope_)
|
||||||
|
{
|
||||||
|
writeln("Resolving type of ", symbol.name);
|
||||||
|
Type type = symbol.type;
|
||||||
|
|
||||||
|
// Simple case
|
||||||
|
if (type.type2.builtinType != TokenType.invalid && type.typeSuffixes.length == 0)
|
||||||
|
{
|
||||||
|
return scope_.findSymbolInCurrentScope(cursorPosition, getTokenValue(type.type2.builtinType));
|
||||||
|
}
|
||||||
|
if (type.type2.symbol !is null && type.typeSuffixes.length == 0)
|
||||||
|
{
|
||||||
|
return scope_.findSymbolInCurrentScope(cursorPosition,
|
||||||
|
type.type2.symbol.identifierOrTemplateChain.identifiersOrTemplateInstances[0].identifier.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
T getExpression(T)(T beforeTokens)
|
T getExpression(T)(T beforeTokens)
|
||||||
{
|
{
|
||||||
size_t i = beforeTokens.length - 1;
|
size_t i = beforeTokens.length - 1;
|
||||||
|
@ -187,6 +262,30 @@ T getExpression(T)(T beforeTokens)
|
||||||
{
|
{
|
||||||
with (TokenType) switch (beforeTokens[i].type)
|
with (TokenType) switch (beforeTokens[i].type)
|
||||||
{
|
{
|
||||||
|
case TokenType.int_:
|
||||||
|
case TokenType.uint_:
|
||||||
|
case TokenType.long_:
|
||||||
|
case TokenType.ulong_:
|
||||||
|
case TokenType.char_:
|
||||||
|
case TokenType.wchar_:
|
||||||
|
case TokenType.dchar_:
|
||||||
|
case TokenType.bool_:
|
||||||
|
case TokenType.byte_:
|
||||||
|
case TokenType.ubyte_:
|
||||||
|
case TokenType.short_:
|
||||||
|
case TokenType.ushort_:
|
||||||
|
case TokenType.cent_:
|
||||||
|
case TokenType.ucent_:
|
||||||
|
case TokenType.float_:
|
||||||
|
case TokenType.ifloat_:
|
||||||
|
case TokenType.cfloat_:
|
||||||
|
case TokenType.idouble_:
|
||||||
|
case TokenType.cdouble_:
|
||||||
|
case TokenType.double_:
|
||||||
|
case TokenType.real_:
|
||||||
|
case TokenType.ireal_:
|
||||||
|
case TokenType.creal_:
|
||||||
|
case this_:
|
||||||
case identifier:
|
case identifier:
|
||||||
if (hasSpecialPrefix)
|
if (hasSpecialPrefix)
|
||||||
{
|
{
|
||||||
|
@ -257,3 +356,118 @@ unittest
|
||||||
{
|
{
|
||||||
assert("ClNa".createCamelCaseRegex() == "Cl.*Na.*");
|
assert("ClNa".createCamelCaseRegex() == "Cl.*Na.*");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes builtin types and the various properties of builtin types
|
||||||
|
*/
|
||||||
|
static this()
|
||||||
|
{
|
||||||
|
auto bool_ = new ACSymbol("bool", CompletionKind.keyword);
|
||||||
|
auto int_ = new ACSymbol("int", CompletionKind.keyword);
|
||||||
|
auto long_ = new ACSymbol("long", CompletionKind.keyword);
|
||||||
|
auto byte_ = new ACSymbol("byte", CompletionKind.keyword);
|
||||||
|
auto dchar_ = new ACSymbol("dchar", CompletionKind.keyword);
|
||||||
|
auto short_ = new ACSymbol("short", CompletionKind.keyword);
|
||||||
|
auto ubyte_ = new ACSymbol("ubyte", CompletionKind.keyword);
|
||||||
|
auto uint_ = new ACSymbol("uint", CompletionKind.keyword);
|
||||||
|
auto ulong_ = new ACSymbol("ulong", CompletionKind.keyword);
|
||||||
|
auto ushort_ = new ACSymbol("ushort", CompletionKind.keyword);
|
||||||
|
auto wchar_ = new ACSymbol("wchar", CompletionKind.keyword);
|
||||||
|
|
||||||
|
auto alignof_ = new ACSymbol("alignof", CompletionKind.keyword, ulong_);
|
||||||
|
auto mangleof_ = new ACSymbol("mangleof", CompletionKind.keyword);
|
||||||
|
auto sizeof_ = new ACSymbol("sizeof", CompletionKind.keyword, ulong_);
|
||||||
|
auto stringof_ = new ACSymbol("stringof", CompletionKind.keyword);
|
||||||
|
|
||||||
|
arraySymbols ~= alignof_;
|
||||||
|
arraySymbols ~= new ACSymbol("dup", CompletionKind.keyword);
|
||||||
|
arraySymbols ~= new ACSymbol("idup", CompletionKind.keyword);
|
||||||
|
arraySymbols ~= new ACSymbol("init", CompletionKind.keyword);
|
||||||
|
arraySymbols ~= new ACSymbol("length", CompletionKind.keyword, ulong_);
|
||||||
|
arraySymbols ~= mangleof_;
|
||||||
|
arraySymbols ~= new ACSymbol("ptr", CompletionKind.keyword);
|
||||||
|
arraySymbols ~= new ACSymbol("reverse", CompletionKind.keyword);
|
||||||
|
arraySymbols ~= sizeof_;
|
||||||
|
arraySymbols ~= new ACSymbol("sort", CompletionKind.keyword);
|
||||||
|
arraySymbols ~= stringof_;
|
||||||
|
|
||||||
|
assocArraySymbols ~= alignof_;
|
||||||
|
assocArraySymbols ~= new ACSymbol("byKey", CompletionKind.keyword);
|
||||||
|
assocArraySymbols ~= new ACSymbol("byValue", CompletionKind.keyword);
|
||||||
|
assocArraySymbols ~= new ACSymbol("dup", CompletionKind.keyword);
|
||||||
|
assocArraySymbols ~= new ACSymbol("get", CompletionKind.keyword);
|
||||||
|
assocArraySymbols ~= new ACSymbol("init", CompletionKind.keyword);
|
||||||
|
assocArraySymbols ~= new ACSymbol("keys", CompletionKind.keyword);
|
||||||
|
assocArraySymbols ~= new ACSymbol("length", CompletionKind.keyword, ulong_);
|
||||||
|
assocArraySymbols ~= mangleof_;
|
||||||
|
assocArraySymbols ~= new ACSymbol("rehash", CompletionKind.keyword);
|
||||||
|
arraySymbols ~= sizeof_;
|
||||||
|
arraySymbols ~= stringof_;
|
||||||
|
assocArraySymbols ~= new ACSymbol("values", CompletionKind.keyword);
|
||||||
|
|
||||||
|
foreach (s; [bool_, int_, long_, byte_, dchar_, short_, ubyte_, uint_,
|
||||||
|
ulong_, ushort_, wchar_])
|
||||||
|
{
|
||||||
|
s.parts ~= new ACSymbol("init", CompletionKind.keyword, s);
|
||||||
|
s.parts ~= new ACSymbol("min", CompletionKind.keyword, s);
|
||||||
|
s.parts ~= new ACSymbol("max", CompletionKind.keyword, s);
|
||||||
|
s.parts ~= alignof_;
|
||||||
|
s.parts ~= sizeof_;
|
||||||
|
s.parts ~= stringof_;
|
||||||
|
s.parts ~= mangleof_;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cdouble_ = new ACSymbol("cdouble", CompletionKind.keyword);
|
||||||
|
auto cent_ = new ACSymbol("cent", CompletionKind.keyword);
|
||||||
|
auto cfloat_ = new ACSymbol("cfloat", CompletionKind.keyword);
|
||||||
|
auto char_ = new ACSymbol("char", CompletionKind.keyword);
|
||||||
|
auto creal_ = new ACSymbol("creal", CompletionKind.keyword);
|
||||||
|
auto double_ = new ACSymbol("double", CompletionKind.keyword);
|
||||||
|
auto float_ = new ACSymbol("float", CompletionKind.keyword);
|
||||||
|
auto idouble_ = new ACSymbol("idouble", CompletionKind.keyword);
|
||||||
|
auto ifloat_ = new ACSymbol("ifloat", CompletionKind.keyword);
|
||||||
|
auto ireal_ = new ACSymbol("ireal", CompletionKind.keyword);
|
||||||
|
auto real_ = new ACSymbol("real", CompletionKind.keyword);
|
||||||
|
auto ucent_ = new ACSymbol("ucent", CompletionKind.keyword);
|
||||||
|
|
||||||
|
foreach (s; [cdouble_, cent_, cfloat_, char_, creal_, double_, float_,
|
||||||
|
idouble_, ifloat_, ireal_, real_, ucent_])
|
||||||
|
{
|
||||||
|
s.parts ~= alignof_;
|
||||||
|
s.parts ~= new ACSymbol("dig", CompletionKind.keyword, s);
|
||||||
|
s.parts ~= new ACSymbol("episilon", CompletionKind.keyword, s);
|
||||||
|
s.parts ~= new ACSymbol("infinity", CompletionKind.keyword, s);
|
||||||
|
s.parts ~= new ACSymbol("init", CompletionKind.keyword, s);
|
||||||
|
s.parts ~= mangleof_;
|
||||||
|
s.parts ~= new ACSymbol("mant_dig", CompletionKind.keyword, int_);
|
||||||
|
s.parts ~= new ACSymbol("max", CompletionKind.keyword, s);
|
||||||
|
s.parts ~= new ACSymbol("max_10_exp", CompletionKind.keyword, int_);
|
||||||
|
s.parts ~= new ACSymbol("max_exp", CompletionKind.keyword, int_);
|
||||||
|
s.parts ~= new ACSymbol("min", CompletionKind.keyword, s);
|
||||||
|
s.parts ~= new ACSymbol("min_exp", CompletionKind.keyword, int_);
|
||||||
|
s.parts ~= new ACSymbol("min_10_exp", CompletionKind.keyword, int_);
|
||||||
|
s.parts ~= new ACSymbol("min_normal", CompletionKind.keyword, s);
|
||||||
|
s.parts ~= new ACSymbol("nan", CompletionKind.keyword, s);
|
||||||
|
s.parts ~= sizeof_;
|
||||||
|
s.parts ~= stringof_;
|
||||||
|
}
|
||||||
|
|
||||||
|
ireal_.parts ~= new ACSymbol("im", CompletionKind.keyword, real_);
|
||||||
|
ifloat_.parts ~= new ACSymbol("im", CompletionKind.keyword, float_);
|
||||||
|
idouble_.parts ~= new ACSymbol("im", CompletionKind.keyword, double_);
|
||||||
|
ireal_.parts ~= new ACSymbol("re", CompletionKind.keyword, real_);
|
||||||
|
ifloat_.parts ~= new ACSymbol("re", CompletionKind.keyword, float_);
|
||||||
|
idouble_.parts ~= new ACSymbol("re", CompletionKind.keyword, double_);
|
||||||
|
|
||||||
|
auto void_ = new ACSymbol("void", CompletionKind.keyword);
|
||||||
|
|
||||||
|
builtinSymbols = [bool_, int_, long_, byte_, dchar_, short_, ubyte_, uint_,
|
||||||
|
ulong_, ushort_, wchar_, cdouble_, cent_, cfloat_, char_, creal_, double_,
|
||||||
|
float_, idouble_, ifloat_, ireal_, real_, ucent_, void_];
|
||||||
|
}
|
||||||
|
|
||||||
|
ACSymbol[] builtinSymbols;
|
||||||
|
ACSymbol[] arraySymbols;
|
||||||
|
ACSymbol[] assocArraySymbols;
|
||||||
|
ACSymbol[] classSymbols;
|
||||||
|
ACSymbol[] structSymbols;
|
||||||
|
|
84
constants.d
84
constants.d
|
@ -173,54 +173,6 @@ immutable string[] versions = [
|
||||||
"X86_64"
|
"X86_64"
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
|
||||||
* Properties of all types
|
|
||||||
*/
|
|
||||||
immutable string[] allProperties = [
|
|
||||||
"alignof",
|
|
||||||
"init",
|
|
||||||
"mangleof",
|
|
||||||
"sizeof",
|
|
||||||
"stringof"
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Properties of integer types
|
|
||||||
*/
|
|
||||||
immutable string[] integerProperties = [
|
|
||||||
"alignof",
|
|
||||||
"init",
|
|
||||||
"mangleof",
|
|
||||||
"max",
|
|
||||||
"min",
|
|
||||||
"sizeof",
|
|
||||||
"stringof"
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Properties of floating point types
|
|
||||||
*/
|
|
||||||
immutable string[] floatProperties = [
|
|
||||||
"alignof",
|
|
||||||
"dig",
|
|
||||||
"epsilon",
|
|
||||||
"im",
|
|
||||||
"infinity",
|
|
||||||
"init",
|
|
||||||
"mangleof",
|
|
||||||
"mant_dig",
|
|
||||||
"max",
|
|
||||||
"max_10_exp",
|
|
||||||
"max_exp",
|
|
||||||
"min_10_exp",
|
|
||||||
"min_exp",
|
|
||||||
"min_normal",
|
|
||||||
"nan",
|
|
||||||
"re",
|
|
||||||
"sizeof",
|
|
||||||
"stringof"
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Properties of class types
|
* Properties of class types
|
||||||
*/
|
*/
|
||||||
|
@ -247,39 +199,3 @@ immutable string[] structProperties = [
|
||||||
"sizeof",
|
"sizeof",
|
||||||
"stringof"
|
"stringof"
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
|
||||||
* Properties of arrays
|
|
||||||
*/
|
|
||||||
immutable string[] arrayProperties = [
|
|
||||||
"alignof",
|
|
||||||
"dup",
|
|
||||||
"idup",
|
|
||||||
"init",
|
|
||||||
"length",
|
|
||||||
"mangleof",
|
|
||||||
"ptr",
|
|
||||||
"reverse",
|
|
||||||
"sizeof",
|
|
||||||
"sort",
|
|
||||||
"stringof"
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Properties of associative arrays
|
|
||||||
*/
|
|
||||||
immutable string[] associativeArrayProperties = [
|
|
||||||
"alignof",
|
|
||||||
"byKey",
|
|
||||||
"byValue",
|
|
||||||
"dup",
|
|
||||||
"get",
|
|
||||||
"init",
|
|
||||||
"keys",
|
|
||||||
"length",
|
|
||||||
"mangleof",
|
|
||||||
"rehash",
|
|
||||||
"sizeof",
|
|
||||||
"stringof",
|
|
||||||
"values"
|
|
||||||
];
|
|
||||||
|
|
23
messages.d
23
messages.d
|
@ -32,6 +32,9 @@ enum CompletionKind : char
|
||||||
/// structure names
|
/// structure names
|
||||||
structName = 's',
|
structName = 's',
|
||||||
|
|
||||||
|
/// union name
|
||||||
|
unionName = 'u',
|
||||||
|
|
||||||
/// variable name
|
/// variable name
|
||||||
variableName = 'v',
|
variableName = 'v',
|
||||||
|
|
||||||
|
@ -54,7 +57,13 @@ enum CompletionKind : char
|
||||||
packageName = 'P',
|
packageName = 'P',
|
||||||
|
|
||||||
// module name
|
// module name
|
||||||
moduleName = 'M'
|
moduleName = 'M',
|
||||||
|
|
||||||
|
// array
|
||||||
|
array = 'a',
|
||||||
|
|
||||||
|
// associative array
|
||||||
|
assocArray = 'A',
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,6 +83,13 @@ enum CompletionType : string
|
||||||
calltips = "calltips"
|
calltips = "calltips"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum RequestKind
|
||||||
|
{
|
||||||
|
autocomplete,
|
||||||
|
clearCache,
|
||||||
|
addImport
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Autocompletion request message
|
* Autocompletion request message
|
||||||
*/
|
*/
|
||||||
|
@ -84,6 +100,11 @@ struct AutocompleteRequest
|
||||||
*/
|
*/
|
||||||
string fileName;
|
string fileName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command coming from the client
|
||||||
|
*/
|
||||||
|
RequestKind kind;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Paths to be searched for import files
|
* Paths to be searched for import files
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -21,23 +21,97 @@ module modulecache;
|
||||||
import std.file;
|
import std.file;
|
||||||
import std.datetime;
|
import std.datetime;
|
||||||
|
|
||||||
|
import acvisitor;
|
||||||
|
|
||||||
|
struct CacheEntry
|
||||||
|
{
|
||||||
|
ACSymbol[] symbols;
|
||||||
|
SysTime modificationTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Caches pre-parsed module information.
|
||||||
|
*/
|
||||||
struct ModuleCache
|
struct ModuleCache
|
||||||
{
|
{
|
||||||
@disable this();
|
@disable this();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the completion cache
|
||||||
|
*/
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
cache = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given path to the list of directories checked for imports
|
||||||
|
*/
|
||||||
|
void addImportPath(string path)
|
||||||
|
{
|
||||||
|
importPaths ~= path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Params:
|
||||||
|
* moduleName = the name of the module in "a.b.c" form
|
||||||
|
* Returns:
|
||||||
|
* The symbols defined in the given module
|
||||||
|
*/
|
||||||
|
ACSymbol[] getSymbolsInModule(string moduleName)
|
||||||
|
{
|
||||||
|
string location = resolveImportLoctation(moduleName);
|
||||||
|
if (!needsReparsing(location))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Module mod = parseModule(tokens, location, &doesNothing);
|
||||||
|
auto visitor = new AutocompleteVisitor;
|
||||||
|
visitor.visit(mod);
|
||||||
|
cache[location].mod = visitor.symbols;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Params:
|
||||||
|
* moduleName the name of the module being imported, in "a.b.c" style
|
||||||
|
* Returns:
|
||||||
|
* The absolute path to the file that contains the module, or null if
|
||||||
|
* not found.
|
||||||
|
*/
|
||||||
|
string resolveImportLoctation(string moduleName)
|
||||||
|
{
|
||||||
|
foreach (path; importPaths)
|
||||||
|
{
|
||||||
|
string filePath = path ~ "/" ~ imp;
|
||||||
|
if (filePath.exists())
|
||||||
|
return filePath;
|
||||||
|
filePath ~= "i"; // check for x.di if x.d isn't found
|
||||||
|
if (filePath.exists())
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Params:
|
||||||
|
* mod = the path to the module
|
||||||
|
* Returns:
|
||||||
|
* true if the module needs to be reparsed, false otherwise
|
||||||
|
*/
|
||||||
bool needsReparsing(string mod)
|
bool needsReparsing(string mod)
|
||||||
{
|
{
|
||||||
if (!exists(mod))
|
if (!exists(mod) || mod !in cache)
|
||||||
return false;
|
|
||||||
if (mod !in modificationTimes)
|
|
||||||
return true;
|
return true;
|
||||||
SysTime access;
|
SysTime access;
|
||||||
SysTime modification;
|
SysTime modification;
|
||||||
getTimes(mod, access, modification);
|
getTimes(mod, access, modification);
|
||||||
if (modificationTimes[mod] != modification)
|
return cache[mod].modificationTime != modification;
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SysTime[string] modificationTimes;
|
// Mapping of file paths to their cached symbols.
|
||||||
|
CacheEntry[string] cache;
|
||||||
|
|
||||||
|
// Listing of paths to check for imports
|
||||||
|
string[] importPaths;
|
||||||
}
|
}
|
||||||
|
|
13
server.d
13
server.d
|
@ -79,10 +79,19 @@ int main(string[] args)
|
||||||
writeln("Socket recieve failed");
|
writeln("Socket recieve failed");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
AutocompleteRequest request;
|
AutocompleteRequest request;
|
||||||
msgpack.unpack(buffer[8 .. bytesReceived], request);
|
msgpack.unpack(buffer[8 .. bytesReceived], request);
|
||||||
|
if (request.kind == RequestKind.addImport)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (request.kind == RequestKind.clearCache)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
AutocompleteResponse response = complete(request, importPaths);
|
AutocompleteResponse response = complete(request, importPaths);
|
||||||
ubyte[] responseBytes = msgpack.pack(response);
|
ubyte[] responseBytes = msgpack.pack(response);
|
||||||
assert(s.send(responseBytes) == responseBytes.length);
|
assert(s.send(responseBytes) == responseBytes.length);
|
||||||
|
|
Loading…
Reference in New Issue