diff --git a/README.md b/README.md
index 2e9daa4..79647f4 100644
--- a/README.md
+++ b/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.
-
-Be sure to run ```git submodule update --init``` after cloning this repository.
+#Setup
+Don't. This code is not ready for you to use yet. If you're going to ignore this
+warning, be sure to run ```git submodule update --init``` after cloning this
+repository to grab the MessagePack library.
diff --git a/actypes.d b/actypes.d
index 60e7028..319a386 100644
--- a/actypes.d
+++ b/actypes.d
@@ -23,26 +23,99 @@ import std.algorithm;
import std.stdio;
import messages;
+/**
+ * Autocompletion symbol
+ */
class ACSymbol
{
public:
+
+ this()
+ {
+ }
+
+ 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;
- Type[string] templateParameters;
+
+ /**
+ * 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
{
public:
+ /**
+ * Params:
+ * start = the index of the opening brace
+ * end = the index of the closing brace
+ */
this(size_t start, size_t end)
{
this.start = start;
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);
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;
foreach (sc; children)
{
@@ -72,7 +145,11 @@ public:
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)
{
@@ -84,9 +161,28 @@ public:
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;
+
+ /**
+ * The parent scope
+ */
Scope parent;
+
+ /**
+ * Child scopes
+ */
Scope[] children;
}
diff --git a/acvisitor.d b/acvisitor.d
index 4155e3c..f43df8f 100644
--- a/acvisitor.d
+++ b/acvisitor.d
@@ -1,20 +1,20 @@
/**
-* This file is part of DCD, a development tool for the D programming language.
-* Copyright (C) 2013 Brian Schott
-*
-* This program is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation, either version 3 of the License, or
-* (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program. If not, see .
-*/
+ * This file is part of DCD, a development tool for the D programming language.
+ * Copyright (C) 2013 Brian Schott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
module acvisitor;
@@ -31,21 +31,54 @@ class AutoCompleteVisitor : ASTVisitor
{
alias ASTVisitor.visit visit;
- override void visit(EnumDeclaration enumDec)
+ override void visit(StructDeclaration dec)
{
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;
- auto p = parentSymbol;
- parentSymbol = symbol;
- enumDec.accept(this);
- parentSymbol = p;
- writeln("Added ", symbol.name);
- if (parentSymbol is null)
- symbols ~= symbol;
- else
- parentSymbol.parts ~= symbol;
- scope_.symbols ~= symbol;
+ mixin (visitAndAdd);
+ }
+
+ override void visit(FunctionDeclaration dec)
+ {
+ writeln("Found function declaration ", dec.name.value);
+ auto symbol = new ACSymbol;
+ symbol.name = dec.name.value;
+ symbol.kind = CompletionKind.functionName;
+ mixin (visitAndAdd);
}
override void visit(EnumMember member)
@@ -53,28 +86,47 @@ class AutoCompleteVisitor : ASTVisitor
auto s = new ACSymbol;
s.kind = CompletionKind.enumMember;
s.name = member.name.value;
- writeln("Added enum member ", s.name);
+// writeln("Added enum member ", s.name);
if (parentSymbol !is null)
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)
{
foreach (singleImport; dec.singleImports)
{
- imports ~= flattenIdentifierChain(singleImport.identifierChain);
+ imports ~= convertChainToImportPath(singleImport.identifierChain);
}
if (dec.importBindings !is null)
{
- imports ~= flattenIdentifierChain(dec.importBindings.singleImport.identifierChain);
+ imports ~= convertChainToImportPath(dec.importBindings.singleImport.identifierChain);
}
}
override void visit(BlockStatement blockStatement)
{
+ writeln("Processing block statement");
auto s = scope_;
scope_ = new Scope(blockStatement.startLocation,
blockStatement.endLocation);
+ scope_.parent = s;
blockStatement.accept(this);
s.children ~= scope_;
scope_ = s;
@@ -86,7 +138,7 @@ class AutoCompleteVisitor : ASTVisitor
mod.accept(this);
}
- private static string flattenIdentifierChain(IdentifierChain chain)
+ private static string convertChainToImportPath(IdentifierChain chain)
{
string rVal;
bool first = true;
@@ -104,44 +156,28 @@ class AutoCompleteVisitor : ASTVisitor
ACSymbol[] symbols;
ACSymbol parentSymbol;
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) {}
AutoCompleteVisitor processModule(const(Token)[] tokens)
{
- Module mod = parseModule(tokens, "", &doesNothing);
+ Module mod = parseModule(tokens, "", null/*&doesNothing*/);
auto visitor = new AutoCompleteVisitor;
visitor.visit(mod);
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;
-}
diff --git a/autocomplete.d b/autocomplete.d
index b23d49c..fe44768 100644
--- a/autocomplete.d
+++ b/autocomplete.d
@@ -90,7 +90,12 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
{
switch (beforeTokens[$ - 2].type)
{
- case TokenType.int_:
+ case TokenType.stringLiteral:
+ case TokenType.wstringLiteral:
+ case TokenType.dstringLiteral:
+ // TODO
+ break;
+ case TokenType.int_:
case TokenType.uint_:
case TokenType.long_:
case TokenType.ulong_:
@@ -104,13 +109,6 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
case TokenType.ushort_:
case TokenType.cent_:
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.ifloat_:
case TokenType.cfloat_:
@@ -120,27 +118,11 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
case TokenType.real_:
case TokenType.ireal_:
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.rParen:
case TokenType.rBracket:
auto visitor = processModule(tokenArray);
+ visitor.scope_.symbols ~= builtinSymbols;
auto expression = getExpression(beforeTokens[0..$]);
response.setCompletions(visitor, expression, request.cursorPosition);
break;
@@ -160,23 +142,116 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
}
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.
- if (tokens[0] != TokenType.identifier) return;
- writeln("Getting completions for ", tokens[0].value);
- auto symbol = visitor.scope_.findSymbolInCurrentScope(cursorPosition, tokens[0].value);
+ writeln("Getting completions for ", map!"a.value"(tokens));
+ ACSymbol symbol = visitor.scope_.findSymbolInCurrentScope(cursorPosition, tokens[0].value);
if (symbol is null)
+ {
+ writeln("Could not find declaration of ", tokens[0].value);
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)
{
- writeln("Adding ", s.name, " to the completion list");
+ //writeln("Adding ", s.name, " to the completion list");
response.completionKinds ~= s.kind;
response.completions ~= s.name;
}
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)
{
size_t i = beforeTokens.length - 1;
@@ -187,6 +262,30 @@ T getExpression(T)(T beforeTokens)
{
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:
if (hasSpecialPrefix)
{
@@ -257,3 +356,118 @@ unittest
{
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;
diff --git a/constants.d b/constants.d
index ac9fb24..d562754 100644
--- a/constants.d
+++ b/constants.d
@@ -173,54 +173,6 @@ immutable string[] versions = [
"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
*/
@@ -247,39 +199,3 @@ immutable string[] structProperties = [
"sizeof",
"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"
-];
diff --git a/messages.d b/messages.d
index ee5415c..7b94847 100644
--- a/messages.d
+++ b/messages.d
@@ -32,6 +32,9 @@ enum CompletionKind : char
/// structure names
structName = 's',
+ /// union name
+ unionName = 'u',
+
/// variable name
variableName = 'v',
@@ -54,7 +57,13 @@ enum CompletionKind : char
packageName = 'P',
// module name
- moduleName = 'M'
+ moduleName = 'M',
+
+ // array
+ array = 'a',
+
+ // associative array
+ assocArray = 'A',
}
/**
@@ -74,6 +83,13 @@ enum CompletionType : string
calltips = "calltips"
}
+enum RequestKind
+{
+ autocomplete,
+ clearCache,
+ addImport
+}
+
/**
* Autocompletion request message
*/
@@ -84,6 +100,11 @@ struct AutocompleteRequest
*/
string fileName;
+ /**
+ * Command coming from the client
+ */
+ RequestKind kind;
+
/**
* Paths to be searched for import files
*/
diff --git a/modulecache.d b/modulecache.d
index 68d5fea..fa6003c 100644
--- a/modulecache.d
+++ b/modulecache.d
@@ -21,23 +21,97 @@ module modulecache;
import std.file;
import std.datetime;
+import acvisitor;
+
+struct CacheEntry
+{
+ ACSymbol[] symbols;
+ SysTime modificationTime;
+}
+
+/**
+ * Caches pre-parsed module information.
+ */
struct ModuleCache
{
@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)
{
- if (!exists(mod))
- return false;
- if (mod !in modificationTimes)
+ if (!exists(mod) || mod !in cache)
return true;
SysTime access;
SysTime modification;
getTimes(mod, access, modification);
- if (modificationTimes[mod] != modification)
- return true;
- return false;
+ return cache[mod].modificationTime != modification;
}
- SysTime[string] modificationTimes;
+ // Mapping of file paths to their cached symbols.
+ CacheEntry[string] cache;
+
+ // Listing of paths to check for imports
+ string[] importPaths;
}
diff --git a/server.d b/server.d
index 65c5de1..9447356 100644
--- a/server.d
+++ b/server.d
@@ -79,10 +79,19 @@ int main(string[] args)
writeln("Socket recieve failed");
break;
}
- else
+
+ AutocompleteRequest request;
+ msgpack.unpack(buffer[8 .. bytesReceived], request);
+ if (request.kind == RequestKind.addImport)
+ {
+
+ }
+ else if (request.kind == RequestKind.clearCache)
+ {
+
+ }
+ else
{
- AutocompleteRequest request;
- msgpack.unpack(buffer[8 .. bytesReceived], request);
AutocompleteResponse response = complete(request, importPaths);
ubyte[] responseBytes = msgpack.pack(response);
assert(s.send(responseBytes) == responseBytes.length);