From 814dcbd26ae4a00c459d4ca44e7f0068cf0b285c Mon Sep 17 00:00:00 2001 From: Hackerpilot Date: Wed, 7 Aug 2013 01:36:36 +0000 Subject: [PATCH] Tons of hacking, but not necessarily tons of progress --- README.md | 19 ++-- actypes.d | 112 ++++++++++++++++++-- acvisitor.d | 162 +++++++++++++++++------------ autocomplete.d | 274 +++++++++++++++++++++++++++++++++++++++++++------ constants.d | 84 --------------- messages.d | 23 ++++- modulecache.d | 88 ++++++++++++++-- server.d | 15 ++- 8 files changed, 575 insertions(+), 202 deletions(-) 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);