Tons of hacking, but not necessarily tons of progress

This commit is contained in:
Hackerpilot 2013-08-07 01:36:36 +00:00
parent 267dbab208
commit 814dcbd26a
8 changed files with 575 additions and 202 deletions

View File

@ -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
View File

@ -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;
} }

View File

@ -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;
}

View File

@ -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;

View File

@ -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"
];

View File

@ -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
*/ */

View File

@ -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;
} }

View File

@ -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);