From f458362ae76b6cfb6f8628531f6353b36d594734 Mon Sep 17 00:00:00 2001 From: Hackerpilot Date: Wed, 14 Aug 2013 21:30:41 +0000 Subject: [PATCH] Support alias declarations --- README.md | 6 +- actypes.d | 103 ++++++++++++++++---------- acvisitor.d | 64 +++++++++++++++- autocomplete.d | 39 +++++++++- client.d | 33 +++++---- editors/textadept/modules/dmd/dcd.lua | 43 +++++++++++ messages.d | 9 ++- 7 files changed, 230 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index 57a3a0c..5c7e83e 100644 --- a/README.md +++ b/README.md @@ -15,16 +15,16 @@ back to the client. * Autocompletion of __traits, scope, and extern arguments * Autocompletion of enums * Autocompletion of class, struct, and interface instances. - * Display of call tips for functions and constructors + * Display of call tips for functions, constructors, and variables of function type + * alias declarations * Not working: * Automatic starting of the server by the client * Windows support (I don't know that it won't work, but this program is not tested on Windows yet) * UFCS * Templated declarations - * import statement completions + * *import* statement completions * Fields inherited from super classes or implemented interfaces. * *auto* declarations - * alias declarations * Determining the type of an enum member when no base type is specified, but the first member has an initialaizer * Public imports * That one feature that you *REALLY* needed diff --git a/actypes.d b/actypes.d index 8b4e667..eff7867 100644 --- a/actypes.d +++ b/actypes.d @@ -88,12 +88,12 @@ public: * Symbols that compose this symbol, such as enum members, class variables, * methods, etc. */ - ACSymbol[] parts; + ACSymbol[] parts; /** * Symbol's name */ - string name; + string name; /** * Symbol's location in bytes @@ -108,7 +108,7 @@ public: /** * The kind of symbol */ - CompletionKind kind; + CompletionKind kind; /** * The return type if this is a function, or the element type if this is an @@ -173,35 +173,35 @@ public: return s.findSymbolsInScope(name); } - /** - * Returns: the innermost Scope that contains the given cursor position. - */ - Scope findCurrentScope(size_t cursorPosition) - { - if (start != size_t.max && (cursorPosition < start || cursorPosition > end)) - return null; - foreach (sc; children) - { - auto s = sc.findCurrentScope(cursorPosition); - if (s is null) - continue; - else - return s; - } - return this; - } + /** + * Returns: the innermost Scope that contains the given cursor position. + */ + Scope findCurrentScope(size_t cursorPosition) + { + if (start != size_t.max && (cursorPosition < start || cursorPosition > end)) + return null; + foreach (sc; children) + { + auto s = sc.findCurrentScope(cursorPosition); + if (s is null) + continue; + else + return s; + } + return this; + } /** * Finds a symbol with the given name in this scope or one of its parent * scopes. */ - ACSymbol[] findSymbolsInScope(string name) - { + ACSymbol[] findSymbolsInScope(string name) + { ACSymbol[] currentMatches = symbols.filter!(a => a.name == name)().array(); if (currentMatches.length == 0 && parent !is null) return parent.findSymbolsInScope(name); - return currentMatches; - } + return currentMatches; + } /** * Fills in the $(D resolvedType) fields of the symbols in this scope and @@ -215,34 +215,55 @@ public: // don't have any indirection foreach (ref s; symbols.filter!(a => (a.kind == CompletionKind.variableName || a.kind == CompletionKind.functionName || a.kind == CompletionKind.memberVariableName - || a.kind == CompletionKind.enumMember) && a.resolvedType is null)()) + || a.kind == CompletionKind.enumMember || a.kind == CompletionKind.aliasName) + && a.resolvedType is null)()) { - //writeln("Resolving type of symbol ", s.name); + writeln("Resolving type of symbol ", s.name); Type type = s.type; if (type is null) + { + //writeln("Could not find it due to null type"); continue; + } if (type.type2.builtinType != TokenType.invalid) { + //writeln("It was a built-in type"); // This part is easy. Autocomplete properties of built-in types s.resolvedType = findSymbolsInScope(getTokenValue(type.type2.builtinType))[0]; } else if (type.type2.symbol !is null) { - // Look up a type by its name for cases like class, enum, - // interface, struct, or union members. + // Look up a type by its name for cases like class, enum, + // interface, struct, or union members. - // TODO: Does not work with qualified names or template instances - Symbol sym = type.type2.symbol; - if (sym.identifierOrTemplateChain.identifiersOrTemplateInstances.length != 1) - return; - ACSymbol[] resolvedType = findSymbolsInCurrentScope(s.location, - sym.identifierOrTemplateChain.identifiersOrTemplateInstances[0].identifier.value); - if (resolvedType.length > 0) - s.resolvedType = resolvedType[0]; + // TODO: Does not work with qualified names or template instances + Symbol sym = type.type2.symbol; + if (sym.identifierOrTemplateChain.identifiersOrTemplateInstances.length != 1) + { + writeln("Could not resolve type"); + continue; + } + ACSymbol[] resolvedType = findSymbolsInCurrentScope(s.location, + sym.identifierOrTemplateChain.identifiersOrTemplateInstances[0].identifier.value); + if (resolvedType.length > 0 && (resolvedType[0].kind == CompletionKind.interfaceName + || resolvedType[0].kind == CompletionKind.className + || resolvedType[0].kind == CompletionKind.aliasName + || resolvedType[0].kind == CompletionKind.unionName + || resolvedType[0].kind == CompletionKind.structName)) + { + writeln("Type resolved to ", resolvedType[0].name, " which has kind ", + resolvedType[0].kind, " and call tip ", resolvedType[0].calltip); + s.resolvedType = resolvedType[0]; + } + } + else + { + writeln(type); } foreach (suffix; type.typeSuffixes) { + //writeln("Handling type suffix"); // Handle type suffixes for declarations, e.g.: // int[] a; // SomeClass[string] b; @@ -280,25 +301,25 @@ public: /** * Index of the opening brace */ - size_t start = size_t.max; + size_t start = size_t.max; /** * Index of the closing brace */ - size_t end = size_t.max; + 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; } diff --git a/acvisitor.d b/acvisitor.d index 0724a90..6497cf1 100644 --- a/acvisitor.d +++ b/acvisitor.d @@ -256,11 +256,22 @@ class AutocompleteVisitor : ASTVisitor // writeln("VariableDeclaration visit"); foreach (d; dec.declarators) { - auto symbol = new ACSymbol; + ACSymbol symbol = new ACSymbol; + if (dec.type.typeSuffixes.length > 0 + && dec.type.typeSuffixes[$-1].delegateOrFunction != TokenType.invalid) + { + TypeSuffix suffix = dec.type.typeSuffixes[$ - 1]; + dec.type.typeSuffixes = dec.type.typeSuffixes[0 .. $ - 1]; + symbol.calltip = "%s %s%s".format(dec.type, + suffix.delegateOrFunction.value, + suffix.parameters.toString()); + } + symbol.kind = CompletionKind.variableName; + symbol.type = dec.type; symbol.name = d.name.value; symbol.location = d.name.startIndex; - symbol.kind = CompletionKind.variableName; + if (parentSymbol is null) symbols ~= symbol; else @@ -269,6 +280,55 @@ class AutocompleteVisitor : ASTVisitor } } + override void visit(AliasDeclaration dec) + { + if (dec.type is null) foreach (aliasPart; dec.initializers) + { + ACSymbol aliasSymbol = new ACSymbol; + aliasSymbol.kind = CompletionKind.aliasName; + aliasSymbol.location = aliasPart.name.startIndex; + aliasSymbol.type = aliasPart.type; + if (aliasPart.type.typeSuffixes.length > 0 + && aliasPart.type.typeSuffixes[$-1].delegateOrFunction != TokenType.invalid) + { + TypeSuffix suffix = aliasPart.type.typeSuffixes[$ - 1]; + aliasPart.type.typeSuffixes = aliasPart.type.typeSuffixes[0 .. $ - 1]; + aliasSymbol.calltip = "%s %s%s".format(dec.type, + suffix.delegateOrFunction.value, + suffix.parameters.toString()); + } + if (parentSymbol is null) + symbols ~= aliasSymbol; + else + parentSymbol.parts ~= aliasSymbol; + scope_.symbols ~= aliasSymbol; + } + else + { +// writeln("Visiting alias declaration ", dec.name.value); + ACSymbol aliasSymbol = new ACSymbol; + aliasSymbol.kind = CompletionKind.aliasName; + aliasSymbol.name = dec.name.value; + aliasSymbol.type = dec.type; + if (dec.type.typeSuffixes.length > 0 + && dec.type.typeSuffixes[$-1].delegateOrFunction != TokenType.invalid) + { + TypeSuffix suffix = dec.type.typeSuffixes[$ - 1]; + dec.type.typeSuffixes = dec.type.typeSuffixes[0 .. $ - 1]; + aliasSymbol.calltip = "%s %s%s".format(dec.type, + suffix.delegateOrFunction.value, + suffix.parameters.toString()); + } + aliasSymbol.location = dec.name.startIndex; + if (parentSymbol is null) + symbols ~= aliasSymbol; + else + parentSymbol.parts ~= aliasSymbol; + scope_.symbols ~= aliasSymbol; + } + + } + override void visit(ImportDeclaration dec) { // TODO: handle public imports diff --git a/autocomplete.d b/autocomplete.d index 3ade365..b51b91b 100644 --- a/autocomplete.d +++ b/autocomplete.d @@ -163,11 +163,15 @@ void setCompletions(T)(ref AutocompleteResponse response, if (completionType == CompletionType.identifiers && symbols[0].kind == CompletionKind.memberVariableName || symbols[0].kind == CompletionKind.variableName + || symbols[0].kind == CompletionKind.aliasName || symbols[0].kind == CompletionKind.enumMember) { symbols = symbols[0].resolvedType is null ? [] : [symbols[0].resolvedType]; if (symbols.length == 0) + { + //writeln("Could not figure it out"); return; + } } loop: for (size_t i = 1; i < tokens.length; i++) @@ -223,7 +227,7 @@ void setCompletions(T)(ref AutocompleteResponse response, symbols = symbols[0].getPartsByName(tokens[i].value); if (symbols.length == 0) { - //writeln("Couldn't find it."); +// writeln("Couldn't find it."); break loop; } if (symbols[0].kind == CompletionKind.variableName @@ -233,7 +237,18 @@ void setCompletions(T)(ref AutocompleteResponse response, && (completionType == CompletionType.identifiers || i + 1 < tokens.length))) { - symbols = symbols[0].resolvedType is null ? [] :[symbols[0].resolvedType]; + symbols = symbols[0].resolvedType is null ? [] : [symbols[0].resolvedType]; + } + if (symbols[0].kind == CompletionKind.aliasName + && (completionType == CompletionType.identifiers + || i + 1 < tokens.length)) + { + symbols = symbols[0].resolvedType is null ? [] : [symbols[0].resolvedType]; + } + if (symbols.length == 0) + { +// writeln("Couldn't find it."); + break loop; } break; case lParen: @@ -303,7 +318,9 @@ void setCompletions(T)(ref AutocompleteResponse response, } else if (completionType == CompletionType.calltips) { - if (symbols[0].kind != CompletionKind.functionName) + //writeln("Showing call tips for ", symbols[0].name, " of type ", symbols[0].kind); + if (symbols[0].kind != CompletionKind.functionName + && symbols[0].calltip is null) { auto call = symbols[0].getPartsByName("opCall"); if (call.length == 0) @@ -386,6 +403,7 @@ T getExpression(T)(T beforeTokens) open = rBracket; close = lBracket; skip: + auto bookmark = i; int depth = 1; do { @@ -398,6 +416,21 @@ T getExpression(T)(T beforeTokens) else if (beforeTokens[i].type == close) depth--; } while (true); + // check the current token after skipping parens to the left. + // if it's a loop keyword, pretend we never skipped the parens. + if (i > 0) switch (beforeTokens[i - 1].type) + { + case TokenType.if_: + case TokenType.while_: + case TokenType.for_: + case TokenType.foreach_: + case TokenType.foreach_reverse_: + case TokenType.do_: + i = bookmark + 1; + break expressionLoop; + default: + break; + } break; default: if (hasSpecialPrefix) diff --git a/client.d b/client.d index a66bfa4..9feb183 100644 --- a/client.d +++ b/client.d @@ -150,21 +150,24 @@ int main(string[] args) AutocompleteResponse response; msgpack.unpack(buffer[0..bytesReceived], response); - writeln(response.completionType); - if (response.completionType == CompletionType.identifiers) - { - for (size_t i = 0; i < response.completions.length; i++) - { - writefln("%s\t%s", response.completions[i], response.completionKinds[i]); - } - } - else - { - foreach (completion; response.completions) - { - writeln(completion); - } - } + if (response.completions.length > 0) + { + writeln(response.completionType); + if (response.completionType == CompletionType.identifiers) + { + for (size_t i = 0; i < response.completions.length; i++) + { + writefln("%s\t%s", response.completions[i], response.completionKinds[i]); + } + } + else + { + foreach (completion; response.completions) + { + writeln(completion); + } + } + } return 0; } diff --git a/editors/textadept/modules/dmd/dcd.lua b/editors/textadept/modules/dmd/dcd.lua index 4951b22..ece4a27 100644 --- a/editors/textadept/modules/dmd/dcd.lua +++ b/editors/textadept/modules/dmd/dcd.lua @@ -16,6 +16,7 @@ function M.registerImages() buffer:register_image(8, M.STRUCT) buffer:register_image(9, M.INTERFACE) buffer:register_image(10, M.ENUM) + buffer:register_image(11, M.ALIAS) end local function showCompletionList(r) @@ -50,6 +51,8 @@ local function showCompletionList(r) completion = completion .. "?4" elseif kind == "P" then completion = completion .. "?3" + elseif kind == "l" then + completion = completion .. "?11" end completions[#completions + 1] = completion end @@ -111,6 +114,7 @@ function M.autocomplete(ch) local command = M.PATH_TO_DCD_CLIENT .. " -c" .. buffer.current_pos .. " " .. fileName local p = io.popen(command, "r") local r = p:read("*a") + --print(r) if r ~= "\n" then if r:match("^identifiers.*") then showCompletionList(r) @@ -122,6 +126,45 @@ function M.autocomplete(ch) end end +M.ALIAS =[[ +/* XPM */ +static char * alias_xpm[] = { +"16 16 17 1", +" c None", +". c #547AA0", +"+ c #547BA2", +"@ c #547CA4", +"# c #F0F0F0", +"$ c #547DA6", +"% c #F5F5F5", +"& c #547EA8", +"* c #FBFBFB", +"= c #F7F7F7", +"- c #F2F2F2", +"; c #547BA3", +"> c #ECECEC", +", c #547AA1", +"' c #E7E7E7", +") c #54799F", +"! c #54789D", +" ", +" ", +" .......... ", +" ++++++++++++ ", +" @@@@@##@@@@@ ", +" $$$$%%%%$$$$ ", +" &&&&****&&&& ", +" &&&==&&==&&& ", +" $$$==$$==$$$ ", +" @@@------@@@ ", +" ;;>>>>>>>>;; ", +" ,,'',,,,'',, ", +" )))))))))))) ", +" !!!!!!!!!! ", +" ", +" "}; +]] + -- union icon M.UNION = [[ /* XPM */ diff --git a/messages.d b/messages.d index 9134e18..613eeec 100644 --- a/messages.d +++ b/messages.d @@ -56,14 +56,17 @@ enum CompletionKind : char /// package name packageName = 'P', - // module name + /// module name moduleName = 'M', - // array + /// array array = 'a', - // associative array + /// associative array assocArray = 'A', + + /// alias name + aliasName = 'l', } /**