Created
February 3, 2023 18:30
-
-
Save ryuukk/e82474927be68ddb5638b49b847f4ab7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module dsymbol.conversion.third; | |
import dsymbol.modulecache; | |
import dsymbol.scope_; | |
import dsymbol.semantic; | |
import dsymbol.symbol; | |
import dsymbol.string_interning; | |
import dsymbol.deferred; | |
import containers.hashset; | |
import std.string; | |
import std.array; | |
import std.logger; | |
void thirdPass(Scope* mscope, ref ModuleCache cache, size_t cursorPosition) | |
{ | |
auto desired = mscope.getScopeByCursor(cursorPosition); | |
tryResolve(desired, cache); | |
} | |
bool tryResolveTemplate(Scope* sc, ref ModuleCache cache, DSymbol* item) | |
{ | |
auto fnCT = item.typeSymbolName; | |
if(fnCT is null) | |
return false; | |
if (auto spaceIndex = fnCT.indexOf(" ") > 0) | |
{ | |
bool hasParen = false; | |
bool isTemplate = false; | |
auto retPart = fnCT[0 .. spaceIndex]; | |
auto fnPart = fnCT[spaceIndex .. $]; | |
for(int i = 0; i < fnPart.length; i++) | |
{ | |
if(fnPart[i] ==')') | |
{ | |
if (hasParen) | |
{ | |
isTemplate = true; | |
break; | |
} | |
hasParen = true; | |
} | |
} | |
if (isTemplate) | |
{ | |
auto returnTypePtr = retPart[$-1] == '*'; | |
auto returnTypeArr = retPart[$-1] == ']'; | |
auto returnTypeConst = retPart.length > 6 ? retPart[0 .. 6] == "const(" : false; | |
auto returnTypeInout = retPart.length > 6 ? retPart[0 .. 6] == "inout(" : false; | |
if (returnTypeConst || returnTypeInout) | |
{ | |
retPart = retPart[retPart.indexOf("(") + 1 .. $]; | |
retPart = retPart[0 .. retPart.indexOf(")")]; | |
} | |
if (returnTypePtr) | |
{ | |
retPart = retPart[0 .. $ - 1]; | |
} | |
auto typesStr = fnPart[ fnPart.indexOf('(') + 1 .. $ ]; | |
typesStr = typesStr[0 .. typesStr.indexOf(')') ]; | |
auto typesSplit = split(typesStr, ','); | |
foreach(i, t; typesSplit) | |
{ | |
auto cleanType = t.strip; | |
if (retPart == cleanType) | |
{ | |
if (item.remainingCrumbs.length >= (i+1)) | |
{ | |
auto typeName = item.remainingCrumbs[i]; | |
auto result = sc.getSymbolsAtGlobalScope(istring(typeName)); | |
if (result.length > 0) | |
{ | |
item.type = result[0]; | |
item.ownType = false; | |
return true; | |
} | |
else | |
{ | |
if (item.symbolFile is null || item.symbolFile == "stdin") | |
return false; | |
auto moduleSymbol = cache.getModuleSymbol(item.symbolFile); | |
auto first = moduleSymbol.getFirstPartNamed(istring(typeName)); | |
if (first !is null) | |
{ | |
item.type = first; | |
item.ownType = false; | |
return true; | |
} | |
else | |
return false; | |
} | |
} | |
break; | |
} | |
} | |
} | |
} | |
return false; | |
} | |
void tryResolve(Scope* sc, ref ModuleCache cache) | |
{ | |
if (sc is null) return; | |
auto symbols = sc.symbols; | |
foreach (item; symbols) | |
{ | |
DSymbol* target = item.type; | |
if (target !is null) | |
{ | |
HashSet!size_t visited; | |
foreach (part; target.opSlice()) | |
{ | |
resolvePart(cache, part, sc, visited); | |
} | |
} | |
if (item.remainingCrumbs.length > 0) | |
{ | |
if (tryResolveTemplate(sc, cache, item)) | |
{ | |
item.remainingCrumbs = null; | |
continue; | |
} | |
} | |
// try resolve auto variables | |
if (item.kind == CompletionKind.variableName && item.type !is null) | |
{ | |
auto type = item.type; | |
while (type) | |
{ | |
if (type.kind == CompletionKind.variableName) | |
type = type.type; | |
else break; | |
} | |
item.type = type; | |
} | |
} | |
if (sc.parent !is null) tryResolve(sc.parent, cache); | |
} | |
void resolvePart(ref ModuleCache cache, DSymbol* part, Scope* sc, ref HashSet!size_t visited) | |
{ | |
if (visited.contains(cast(size_t) part)) | |
return; | |
visited.insert(cast(size_t) part); | |
// no type but a callTip, let's resolve its type | |
if (part.type is null && part.typeSymbolName !is null) | |
{ | |
import std.string: indexOf; | |
auto typeName = part.typeSymbolName; | |
// check if it is available in the scope | |
// otherwise grab its module symbol to check if it's publickly available | |
auto result = sc.getSymbolsAtGlobalScope(istring(typeName)); | |
if (result.length > 0) | |
{ | |
part.type = result[$-1]; | |
part.ownType = false; | |
return; | |
} | |
else | |
{ | |
if (part.symbolFile is null || part.symbolFile == "stdin") | |
return; | |
auto moduleSymbol = cache.getModuleSymbol(part.symbolFile); | |
auto first = moduleSymbol.getFirstPartNamed(istring(typeName)); | |
if (first !is null) | |
{ | |
part.type = first; | |
part.ownType = false; | |
return; | |
} | |
else | |
return; | |
} | |
} | |
if (part.type !is null) | |
{ | |
foreach (typePart; part.type.opSlice()) | |
{ | |
resolvePart(cache, typePart, sc, visited); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment