Support alias declarations

This commit is contained in:
Hackerpilot 2013-08-14 21:30:41 +00:00
parent 2bf29e877a
commit f458362ae7
7 changed files with 230 additions and 67 deletions

View File

@ -15,16 +15,16 @@ back to the client.
* Autocompletion of __traits, scope, and extern arguments * Autocompletion of __traits, scope, and extern arguments
* Autocompletion of enums * Autocompletion of enums
* Autocompletion of class, struct, and interface instances. * 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: * Not working:
* Automatic starting of the server by the client * 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) * Windows support (I don't know that it won't work, but this program is not tested on Windows yet)
* UFCS * UFCS
* Templated declarations * Templated declarations
* import statement completions * *import* statement completions
* Fields inherited from super classes or implemented interfaces. * Fields inherited from super classes or implemented interfaces.
* *auto* declarations * *auto* declarations
* alias declarations
* Determining the type of an enum member when no base type is specified, but the first member has an initialaizer * Determining the type of an enum member when no base type is specified, but the first member has an initialaizer
* Public imports * Public imports
* That one feature that you *REALLY* needed * That one feature that you *REALLY* needed

103
actypes.d
View File

@ -88,12 +88,12 @@ public:
* Symbols that compose this symbol, such as enum members, class variables, * Symbols that compose this symbol, such as enum members, class variables,
* methods, etc. * methods, etc.
*/ */
ACSymbol[] parts; ACSymbol[] parts;
/** /**
* Symbol's name * Symbol's name
*/ */
string name; string name;
/** /**
* Symbol's location in bytes * Symbol's location in bytes
@ -108,7 +108,7 @@ public:
/** /**
* The kind of symbol * The kind of symbol
*/ */
CompletionKind kind; CompletionKind kind;
/** /**
* The return type if this is a function, or the element type if this is an * 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); return s.findSymbolsInScope(name);
} }
/** /**
* Returns: the innermost Scope that contains the given cursor position. * Returns: the innermost Scope that contains the given cursor position.
*/ */
Scope findCurrentScope(size_t cursorPosition) Scope findCurrentScope(size_t cursorPosition)
{ {
if (start != size_t.max && (cursorPosition < start || cursorPosition > end)) if (start != size_t.max && (cursorPosition < start || cursorPosition > end))
return null; return null;
foreach (sc; children) foreach (sc; children)
{ {
auto s = sc.findCurrentScope(cursorPosition); auto s = sc.findCurrentScope(cursorPosition);
if (s is null) if (s is null)
continue; continue;
else else
return s; return s;
} }
return this; return this;
} }
/** /**
* Finds a symbol with the given name in this scope or one of its parent * Finds a symbol with the given name in this scope or one of its parent
* scopes. * scopes.
*/ */
ACSymbol[] findSymbolsInScope(string name) ACSymbol[] findSymbolsInScope(string name)
{ {
ACSymbol[] currentMatches = symbols.filter!(a => a.name == name)().array(); ACSymbol[] currentMatches = symbols.filter!(a => a.name == name)().array();
if (currentMatches.length == 0 && parent !is null) if (currentMatches.length == 0 && parent !is null)
return parent.findSymbolsInScope(name); return parent.findSymbolsInScope(name);
return currentMatches; return currentMatches;
} }
/** /**
* Fills in the $(D resolvedType) fields of the symbols in this scope and * Fills in the $(D resolvedType) fields of the symbols in this scope and
@ -215,34 +215,55 @@ public:
// don't have any indirection // don't have any indirection
foreach (ref s; symbols.filter!(a => (a.kind == CompletionKind.variableName foreach (ref s; symbols.filter!(a => (a.kind == CompletionKind.variableName
|| a.kind == CompletionKind.functionName || a.kind == CompletionKind.memberVariableName || 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; Type type = s.type;
if (type is null) if (type is null)
{
//writeln("Could not find it due to null type");
continue; continue;
}
if (type.type2.builtinType != TokenType.invalid) if (type.type2.builtinType != TokenType.invalid)
{ {
//writeln("It was a built-in type");
// This part is easy. Autocomplete properties of built-in types // This part is easy. Autocomplete properties of built-in types
s.resolvedType = findSymbolsInScope(getTokenValue(type.type2.builtinType))[0]; s.resolvedType = findSymbolsInScope(getTokenValue(type.type2.builtinType))[0];
} }
else if (type.type2.symbol !is null) else if (type.type2.symbol !is null)
{ {
// Look up a type by its name for cases like class, enum, // Look up a type by its name for cases like class, enum,
// interface, struct, or union members. // interface, struct, or union members.
// TODO: Does not work with qualified names or template instances // TODO: Does not work with qualified names or template instances
Symbol sym = type.type2.symbol; Symbol sym = type.type2.symbol;
if (sym.identifierOrTemplateChain.identifiersOrTemplateInstances.length != 1) if (sym.identifierOrTemplateChain.identifiersOrTemplateInstances.length != 1)
return; {
ACSymbol[] resolvedType = findSymbolsInCurrentScope(s.location, writeln("Could not resolve type");
sym.identifierOrTemplateChain.identifiersOrTemplateInstances[0].identifier.value); continue;
if (resolvedType.length > 0) }
s.resolvedType = resolvedType[0]; 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) foreach (suffix; type.typeSuffixes)
{ {
//writeln("Handling type suffix");
// Handle type suffixes for declarations, e.g.: // Handle type suffixes for declarations, e.g.:
// int[] a; // int[] a;
// SomeClass[string] b; // SomeClass[string] b;
@ -280,25 +301,25 @@ public:
/** /**
* Index of the opening brace * Index of the opening brace
*/ */
size_t start = size_t.max; size_t start = size_t.max;
/** /**
* Index of the closing brace * Index of the closing brace
*/ */
size_t end = size_t.max; size_t end = size_t.max;
/** /**
* Symbols contained in this scope * Symbols contained in this scope
*/ */
ACSymbol[] symbols; ACSymbol[] symbols;
/** /**
* The parent scope * The parent scope
*/ */
Scope parent; Scope parent;
/** /**
* Child scopes * Child scopes
*/ */
Scope[] children; Scope[] children;
} }

View File

@ -256,11 +256,22 @@ class AutocompleteVisitor : ASTVisitor
// writeln("VariableDeclaration visit"); // writeln("VariableDeclaration visit");
foreach (d; dec.declarators) 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.type = dec.type;
symbol.name = d.name.value; symbol.name = d.name.value;
symbol.location = d.name.startIndex; symbol.location = d.name.startIndex;
symbol.kind = CompletionKind.variableName;
if (parentSymbol is null) if (parentSymbol is null)
symbols ~= symbol; symbols ~= symbol;
else 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) override void visit(ImportDeclaration dec)
{ {
// TODO: handle public imports // TODO: handle public imports

View File

@ -163,11 +163,15 @@ void setCompletions(T)(ref AutocompleteResponse response,
if (completionType == CompletionType.identifiers if (completionType == CompletionType.identifiers
&& symbols[0].kind == CompletionKind.memberVariableName && symbols[0].kind == CompletionKind.memberVariableName
|| symbols[0].kind == CompletionKind.variableName || symbols[0].kind == CompletionKind.variableName
|| symbols[0].kind == CompletionKind.aliasName
|| symbols[0].kind == CompletionKind.enumMember) || symbols[0].kind == CompletionKind.enumMember)
{ {
symbols = symbols[0].resolvedType is null ? [] : [symbols[0].resolvedType]; symbols = symbols[0].resolvedType is null ? [] : [symbols[0].resolvedType];
if (symbols.length == 0) if (symbols.length == 0)
{
//writeln("Could not figure it out");
return; return;
}
} }
loop: for (size_t i = 1; i < tokens.length; i++) 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); symbols = symbols[0].getPartsByName(tokens[i].value);
if (symbols.length == 0) if (symbols.length == 0)
{ {
//writeln("Couldn't find it."); // writeln("Couldn't find it.");
break loop; break loop;
} }
if (symbols[0].kind == CompletionKind.variableName if (symbols[0].kind == CompletionKind.variableName
@ -233,7 +237,18 @@ void setCompletions(T)(ref AutocompleteResponse response,
&& (completionType == CompletionType.identifiers && (completionType == CompletionType.identifiers
|| i + 1 < tokens.length))) || 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; break;
case lParen: case lParen:
@ -303,7 +318,9 @@ void setCompletions(T)(ref AutocompleteResponse response,
} }
else if (completionType == CompletionType.calltips) 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"); auto call = symbols[0].getPartsByName("opCall");
if (call.length == 0) if (call.length == 0)
@ -386,6 +403,7 @@ T getExpression(T)(T beforeTokens)
open = rBracket; open = rBracket;
close = lBracket; close = lBracket;
skip: skip:
auto bookmark = i;
int depth = 1; int depth = 1;
do do
{ {
@ -398,6 +416,21 @@ T getExpression(T)(T beforeTokens)
else if (beforeTokens[i].type == close) else if (beforeTokens[i].type == close)
depth--; depth--;
} while (true); } 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; break;
default: default:
if (hasSpecialPrefix) if (hasSpecialPrefix)

View File

@ -150,21 +150,24 @@ int main(string[] args)
AutocompleteResponse response; AutocompleteResponse response;
msgpack.unpack(buffer[0..bytesReceived], response); msgpack.unpack(buffer[0..bytesReceived], response);
writeln(response.completionType); if (response.completions.length > 0)
if (response.completionType == CompletionType.identifiers) {
{ writeln(response.completionType);
for (size_t i = 0; i < response.completions.length; i++) if (response.completionType == CompletionType.identifiers)
{ {
writefln("%s\t%s", response.completions[i], response.completionKinds[i]); 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) else
{ {
writeln(completion); foreach (completion; response.completions)
} {
} writeln(completion);
}
}
}
return 0; return 0;
} }

View File

@ -16,6 +16,7 @@ function M.registerImages()
buffer:register_image(8, M.STRUCT) buffer:register_image(8, M.STRUCT)
buffer:register_image(9, M.INTERFACE) buffer:register_image(9, M.INTERFACE)
buffer:register_image(10, M.ENUM) buffer:register_image(10, M.ENUM)
buffer:register_image(11, M.ALIAS)
end end
local function showCompletionList(r) local function showCompletionList(r)
@ -50,6 +51,8 @@ local function showCompletionList(r)
completion = completion .. "?4" completion = completion .. "?4"
elseif kind == "P" then elseif kind == "P" then
completion = completion .. "?3" completion = completion .. "?3"
elseif kind == "l" then
completion = completion .. "?11"
end end
completions[#completions + 1] = completion completions[#completions + 1] = completion
end end
@ -111,6 +114,7 @@ function M.autocomplete(ch)
local command = M.PATH_TO_DCD_CLIENT .. " -c" .. buffer.current_pos .. " " .. fileName local command = M.PATH_TO_DCD_CLIENT .. " -c" .. buffer.current_pos .. " " .. fileName
local p = io.popen(command, "r") local p = io.popen(command, "r")
local r = p:read("*a") local r = p:read("*a")
--print(r)
if r ~= "\n" then if r ~= "\n" then
if r:match("^identifiers.*") then if r:match("^identifiers.*") then
showCompletionList(r) showCompletionList(r)
@ -122,6 +126,45 @@ function M.autocomplete(ch)
end end
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 -- union icon
M.UNION = [[ M.UNION = [[
/* XPM */ /* XPM */

View File

@ -56,14 +56,17 @@ enum CompletionKind : char
/// package name /// package name
packageName = 'P', packageName = 'P',
// module name /// module name
moduleName = 'M', moduleName = 'M',
// array /// array
array = 'a', array = 'a',
// associative array /// associative array
assocArray = 'A', assocArray = 'A',
/// alias name
aliasName = 'l',
} }
/** /**