ufcs function chaining

This commit is contained in:
davu 2022-10-18 14:48:35 +02:00
parent c409670da8
commit e969d2b158
14 changed files with 109 additions and 7 deletions

View File

@ -36,8 +36,9 @@ the issue.)
* *auto* declarations (Mostly) * *auto* declarations (Mostly)
* *with* statements * *with* statements
* Simple UFCS suggestions for concrete types. * Simple UFCS suggestions for concrete types.
* UFCS '.' function chaining with concrete types except string type.
* Not working: * Not working:
* UFCS completion for templates, literals, UFCS function arguments, and '.' chaining with other UFCS functions. * UFCS completion for templates, literals, UFCS function arguments.
* UFCS calltips * UFCS calltips
* Autocompletion of declarations with template arguments (This will work to some extent, but it won't do things like replace T with int) * Autocompletion of declarations with template arguments (This will work to some extent, but it won't do things like replace T with int)
* Determining the type of an enum member when no base type is specified, but the first member has an initializer * Determining the type of an enum member when no base type is specified, but the first member has an initializer
@ -157,6 +158,7 @@ tab character, followed by a completion kind
resolvedType v resolvedType v
calltip v calltip v
getPartByName f getPartByName f
ufcsFunction F
#### Extended output mode #### Extended output mode

View File

@ -37,6 +37,8 @@ import std.experimental.allocator;
import std.experimental.allocator.gc_allocator : GCAllocator; import std.experimental.allocator.gc_allocator : GCAllocator;
import std.experimental.logger; import std.experimental.logger;
import std.typecons : Rebindable; import std.typecons : Rebindable;
import std.array : appender;
import std.range : empty;
/** /**
* First Pass handles the following: * First Pass handles the following:
@ -944,10 +946,23 @@ private:
} }
} }
void setFunctionReturnType(const Type returnType, ref DSymbol acSymbol){
if (returnType !is null)
{
auto app = appender!string();
app.formatNode(returnType);
auto foundSymbols = currentScope.getSymbolsByName(istring(app.data));
if (!foundSymbols.empty){
acSymbol.functionReturnType = foundSymbols[0];
}
}
}
void processParameters(SemanticSymbol* symbol, const Type returnType, void processParameters(SemanticSymbol* symbol, const Type returnType,
string functionName, const Parameters parameters, string functionName, const Parameters parameters,
const TemplateParameters templateParameters) const TemplateParameters templateParameters)
{ {
setFunctionReturnType(returnType, *symbol.acSymbol);
processTemplateParameters(symbol, templateParameters); processTemplateParameters(symbol, templateParameters);
if (parameters !is null) if (parameters !is null)
{ {

View File

@ -386,6 +386,12 @@ struct DSymbol
*/ */
DSymbol*[] functionParameters; DSymbol*[] functionParameters;
/**
*
* Return type of the function
*/
DSymbol* functionReturnType;
private uint _location; private uint _location;
/** /**

View File

@ -558,8 +558,10 @@ void setCompletions(T)(ref AutocompleteResponse response,
DSymbol*[] symbols = getSymbolsByTokenChain(completionScope, tokens, DSymbol*[] symbols = getSymbolsByTokenChain(completionScope, tokens,
cursorPosition, completionType); cursorPosition, completionType);
if (symbols.length == 0) if (symbols.length == 0){
lookupUFCSForDotChaining(completionScope, tokens, cursorPosition, response);
return; return;
}
if (completionType == CompletionType.identifiers) if (completionType == CompletionType.identifiers)
{ {

View File

@ -14,11 +14,15 @@ import dparse.lexer : tok;
import std.regex; import std.regex;
import containers.hashset : HashSet; import containers.hashset : HashSet;
void lookupUFCS(Scope* completionScope, DSymbol* beforeDotSymbol, size_t cursorPosition, ref AutocompleteResponse response) bool lookupUFCS(Scope* completionScope, DSymbol* beforeDotSymbol, size_t cursorPosition, ref AutocompleteResponse response)
{ {
// UFCS completion if (beforeDotSymbol.isInvalidForUFCSCompletion)
return false;
DSymbol*[] ufcsSymbols = getSymbolsForUFCS(completionScope, beforeDotSymbol, cursorPosition); DSymbol*[] ufcsSymbols = getSymbolsForUFCS(completionScope, beforeDotSymbol, cursorPosition);
if (ufcsSymbols.empty)
return false;
response.completions ~= map!(s => createCompletionForUFCS(s))(ufcsSymbols).array; response.completions ~= map!(s => createCompletionForUFCS(s))(ufcsSymbols).array;
return true;
} }
AutocompleteResponse.Completion createCompletionForUFCS(const DSymbol* symbol) AutocompleteResponse.Completion createCompletionForUFCS(const DSymbol* symbol)
@ -169,3 +173,32 @@ bool doUFCSSearch(string beforeToken, string lastToken)
// we do the search if they are different from eachother // we do the search if they are different from eachother
return beforeToken != lastToken; return beforeToken != lastToken;
} }
void lookupUFCSForDotChaining(T)(Scope* completionScope, ref T tokens, size_t cursorPosition, ref AutocompleteResponse response)
{
auto filteredTokens = filter!(t => !t.text.empty)(tokens);
if (filteredTokens.empty)
return;
auto foundTokens = filteredTokens.array;
auto possibleUFCSSymbols = completionScope.getSymbolsByNameAndCursor(istring(null), cursorPosition);
for (auto i = foundTokens.length; i > 0; i--)
{
// Finding function return value type
auto foundSymbols = filter!(s => s.name == foundTokens[i - 1].text && s.kind == CompletionKind
.functionName)(possibleUFCSSymbols);
if (!foundSymbols.empty)
{
auto foundFunctionSymbol = foundSymbols.array.back;
if (foundFunctionSymbol.functionReturnType)
{
if (lookupUFCS(completionScope, foundFunctionSymbol.functionReturnType, cursorPosition, response))
{
response.completionType = CompletionType.identifiers;
}
}
break;
}
}
}

View File

@ -15,4 +15,6 @@ ufcsBarRefConstWrapped F
ufcsBarRefImmuttableWrapped F ufcsBarRefImmuttableWrapped F
ufcsBarReturnScope F ufcsBarReturnScope F
ufcsBarScope F ufcsBarScope F
ufcsGetNumber F
ufcsHello F ufcsHello F
ufcsSelf F

View File

@ -0,0 +1,13 @@
identifiers
hasArgname F
u F
ufcsBar F
ufcsBarRef F
ufcsBarRefConst F
ufcsBarRefConstWrapped F
ufcsBarRefImmuttableWrapped F
ufcsBarReturnScope F
ufcsBarScope F
ufcsGetNumber F
ufcsHello F
ufcsSelf F

View File

@ -0,0 +1,3 @@
identifiers
helloNumber F
isEvenNumber F

View File

@ -0,0 +1,2 @@
identifiers
getBoolToFloat F

View File

@ -0,0 +1,2 @@
identifiers
multiply1000 F

View File

@ -0,0 +1,3 @@
identifiers
helloNumber F
isEvenNumber F

View File

@ -1,4 +1,3 @@
//import foodata;
import fooutils; import fooutils;
void hasArgname(Foo f){ void hasArgname(Foo f){
@ -7,4 +6,9 @@ void main()
{ {
auto foo = Foo(); auto foo = Foo();
foo. foo.
foo.ufcsSelf.
foo.ufcsSelf.ufcsGetNumber(42).
foo.ufcsSelf.ufcsGetNumber(42).isEvenNumber.
foo.ufcsSelf.ufcsGetNumber(42).isEvenNumber.getBoolToFloat.
foo.ufcsSelf.ufcsGetNumber(42).isEvenNumber.getBoolToFloat.multiply1000.
} }

View File

@ -5,6 +5,8 @@ struct Foo {
} }
void u(Foo foo) {} void u(Foo foo) {}
Foo ufcsSelf(ref Foo foo) { return foo; }
int ufcsGetNumber(ref Foo foo, int number) { return number; }
void ufcsHello(ref Foo foo) {} void ufcsHello(ref Foo foo) {}
void ufcsBar(Foo foo, string mama) {} void ufcsBar(Foo foo, string mama) {}
void ufcsBarRef(ref Foo foo, string mama) {} void ufcsBarRef(ref Foo foo, string mama) {}
@ -14,4 +16,7 @@ void ufcsBarRefImmuttableWrapped(ref immutable(Foo) foo, string mama) {}
void ufcsBarScope(ref scope Foo foo, string mama) {} void ufcsBarScope(ref scope Foo foo, string mama) {}
void ufcsBarReturnScope(return scope Foo foo, string mama) {} void ufcsBarReturnScope(return scope Foo foo, string mama) {}
private void ufcsBarPrivate(Foo foo, string message) {} private void ufcsBarPrivate(Foo foo, string message) {}
void helloBar(string message) {} void helloNumber(int message) {}
bool isEvenNumber(int number) { return number % 2 == 0; }
float getBoolToFloat(bool result) { return result ? 1.0 : 0.0; }
int multiply1000(float x) { return x * 1000; }

View File

@ -1,5 +1,15 @@
set -e set -e
set -u set -u
../../bin/dcd-client $1 -c100 -I"$PWD"/fooutils file.d > actual.txt ../../bin/dcd-client $1 -c82 -I"$PWD"/fooutils file.d > actual.txt
../../bin/dcd-client $1 -c97 -I"$PWD"/fooutils file.d > actual2.txt
../../bin/dcd-client $1 -c130 -I"$PWD"/fooutils file.d > actual3.txt
../../bin/dcd-client $1 -c176 -I"$PWD"/fooutils file.d > actual4.txt
../../bin/dcd-client $1 -c237 -I"$PWD"/fooutils file.d > actual5.txt
../../bin/dcd-client $1 -c311 -I"$PWD"/fooutils file.d > actual6.txt
diff actual.txt expected.txt diff actual.txt expected.txt
diff actual2.txt expected2.txt
diff actual3.txt expected3.txt
diff actual4.txt expected4.txt
diff actual5.txt expected5.txt
diff actual6.txt expected6.txt