This commit is contained in:
ryuukk 2023-11-18 17:04:45 -07:00 committed by GitHub
commit 855f5e87af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 1215 additions and 17 deletions

View File

@ -39,6 +39,7 @@ import std.experimental.allocator.gc_allocator : GCAllocator;
import std.experimental.logger; import std.experimental.logger;
import std.meta : AliasSeq; import std.meta : AliasSeq;
import std.typecons : Rebindable; import std.typecons : Rebindable;
import std.stdio;
/** /**
* First Pass handles the following: * First Pass handles the following:
@ -239,9 +240,238 @@ final class FirstPass : ASTVisitor
symbol.acSymbol.protection = protection.current; symbol.acSymbol.protection = protection.current;
} }
void processIdentifierOrTemplate(SemanticSymbol* symbol, TypeLookup* lookup, VariableContext* ctx, VariableContext.TypeInstance* current, IdentifierOrTemplateInstance ioti)
{
if (ioti.identifier != tok!"")
current.chain ~= ioti.identifier.text;
else if (ioti.templateInstance)
processTemplateInstance(symbol, lookup, ctx, current, ioti.templateInstance);
}
void processTypeIdentifierPart(SemanticSymbol* symbol, TypeLookup* lookup, VariableContext* ctx, VariableContext.TypeInstance* current, TypeIdentifierPart tip)
{
if (tip.identifierOrTemplateInstance)
{
processIdentifierOrTemplate(symbol, lookup, ctx, current, tip.identifierOrTemplateInstance);
if (current)
{
current.calltip = buildCalltip(tip.identifierOrTemplateInstance.tokens);
}
}
if (tip.typeIdentifierPart)
{
processTypeIdentifierPart(symbol, lookup, ctx, current, tip.typeIdentifierPart);
}
// TODO: handle `tip.dot` and `tip.indexer`
}
void processTemplateArguments(SemanticSymbol* symbol, TypeLookup* lookup, VariableContext* ctx, VariableContext.TypeInstance* current, TemplateArguments targs)
{
if (targs.namedTemplateArgumentList)
{
foreach(i, targ; targs.namedTemplateArgumentList.items)
{
// TODO: handle targ.assignExpression
if (targ.type is null) continue;
if (targ.type.type2 is null) continue;
auto part = targ.type.type2.typeIdentifierPart;
if (part is null)
{
if (targ.type.type2.builtinType == tok!"") continue;
auto builtInName = getBuiltinTypeName(targ.type.type2.builtinType);
auto newArg = GCAllocator.instance.make!(VariableContext.TypeInstance)();
newArg.chain ~= builtInName;
current.args ~= newArg;
continue;
}
auto newArg = GCAllocator.instance.make!(VariableContext.TypeInstance)();
current.args ~= newArg;
if (part.identifierOrTemplateInstance)
{
processIdentifierOrTemplate(symbol, lookup, ctx, newArg, part.identifierOrTemplateInstance);
}
if (part.typeIdentifierPart)
{
if (part.typeIdentifierPart.identifierOrTemplateInstance)
processIdentifierOrTemplate(symbol, lookup, ctx, newArg, part.typeIdentifierPart.identifierOrTemplateInstance);
}
foreach(suffix; targ.type.typeSuffixes)
{
if (suffix.type)
current.calltip ~= "[.]";
else if (suffix.array)
current.calltip ~= "[]";
else if (suffix.star != tok!"")
current.calltip ~= "*";
}
}
}
else if (targs.templateSingleArgument)
{
auto singleArg = targs.templateSingleArgument;
auto arg = GCAllocator.instance.make!(VariableContext.TypeInstance)();
arg.name = singleArg.token.text;
arg.chain ~= arg.name;
current.args ~= arg;
}
}
void processTemplateInstance(SemanticSymbol* symbol, TypeLookup* lookup, VariableContext* ctx, VariableContext.TypeInstance* current, TemplateInstance ti)
{
if (ti.identifier != tok!"")
current.chain ~= ti.identifier.text;
if (ti.templateArguments)
processTemplateArguments(symbol, lookup, ctx, current, ti.templateArguments);
}
void buildChain(SemanticSymbol* symbol, TypeLookup* lookup, VariableContext* ctx, TypeIdentifierPart tip)
{
if (tip.identifierOrTemplateInstance)
buildChainTemplateOrIdentifier(symbol, lookup, ctx, tip.identifierOrTemplateInstance);
if (tip.typeIdentifierPart)
buildChain(symbol, lookup, ctx, tip.typeIdentifierPart);
// TODO: handle `tip.indexer`
}
void buildChainTemplateOrIdentifier(SemanticSymbol* symbol, TypeLookup* lookup, VariableContext* ctx, IdentifierOrTemplateInstance iot)
{
if (iot.templateInstance)
{
if (iot.templateInstance.identifier != tok!"")
lookup.breadcrumbs.insert(istring(iot.templateInstance.identifier.text));
// TODO: finish handling `iot.templateInstance.templateArguments`
if (iot.templateInstance.templateArguments)
{
if (iot.templateInstance.templateArguments.templateSingleArgument)
{
auto tsaTok = iot.templateInstance.templateArguments.templateSingleArgument.token;
if (tsaTok.text == "")
lookup.breadcrumbs.insert(istring(str(tsaTok.type)));
// TODO: investigate why this break everything
// else
// lookup.breadcrumbs.insert(istring(tsaTok.text));
}
}
}
else
{
auto crumb = iot.identifier;
lookup.breadcrumbs.insert(istring(crumb.text));
}
}
string buildCalltip(const(Token)[] tokens)
{
string calltip;
foreach(tk; tokens)
{
if (tk == tok!"!")
calltip ~= "!";
else if (tk == tok!"(")
calltip ~= "(";
else if (tk == tok!")")
calltip ~= ")";
else if (tk == tok!"[")
calltip ~= "[";
else if (tk == tok!"]")
calltip ~= "]";
else if (tk == tok!",")
calltip ~= ",";
else if (tk == tok!"*")
calltip ~= "*";
else if (tk == tok!"")
calltip ~= " ";
else
calltip ~= tk.text;
}
return calltip;
}
void traverseUnaryExpression(SemanticSymbol* symbol, TypeLookup* lookup, VariableContext* ctx, UnaryExpression ue)
{
if (PrimaryExpression pe = ue.primaryExpression)
{
if (pe.identifierOrTemplateInstance)
buildChainTemplateOrIdentifier(symbol, lookup, ctx, pe.identifierOrTemplateInstance);
if (pe.basicType != tok!"")
lookup.breadcrumbs.insert(internString(str(pe.basicType.type)));
switch (pe.primary.type)
{
case tok!"identifier":
lookup.breadcrumbs.insert(internString(pe.primary.text));
break;
case tok!"doubleLiteral":
lookup.breadcrumbs.insert(DOUBLE_LITERAL_SYMBOL_NAME);
break;
case tok!"floatLiteral":
lookup.breadcrumbs.insert(FLOAT_LITERAL_SYMBOL_NAME);
break;
case tok!"idoubleLiteral":
lookup.breadcrumbs.insert(IDOUBLE_LITERAL_SYMBOL_NAME);
break;
case tok!"ifloatLiteral":
lookup.breadcrumbs.insert(IFLOAT_LITERAL_SYMBOL_NAME);
break;
case tok!"intLiteral":
lookup.breadcrumbs.insert(INT_LITERAL_SYMBOL_NAME);
break;
case tok!"longLiteral":
lookup.breadcrumbs.insert(LONG_LITERAL_SYMBOL_NAME);
break;
case tok!"realLiteral":
lookup.breadcrumbs.insert(REAL_LITERAL_SYMBOL_NAME);
break;
case tok!"irealLiteral":
lookup.breadcrumbs.insert(IREAL_LITERAL_SYMBOL_NAME);
break;
case tok!"uintLiteral":
lookup.breadcrumbs.insert(UINT_LITERAL_SYMBOL_NAME);
break;
case tok!"ulongLiteral":
lookup.breadcrumbs.insert(ULONG_LITERAL_SYMBOL_NAME);
break;
case tok!"characterLiteral":
lookup.breadcrumbs.insert(CHAR_LITERAL_SYMBOL_NAME);
break;
case tok!"dstringLiteral":
lookup.breadcrumbs.insert(DSTRING_LITERAL_SYMBOL_NAME);
break;
case tok!"stringLiteral":
lookup.breadcrumbs.insert(STRING_LITERAL_SYMBOL_NAME);
break;
case tok!"wstringLiteral":
lookup.breadcrumbs.insert(WSTRING_LITERAL_SYMBOL_NAME);
break;
case tok!"false":
case tok!"true":
lookup.breadcrumbs.insert(BOOL_VALUE_SYMBOL_NAME);
break;
default:
break;
}
}
if (IdentifierOrTemplateInstance iot = ue.identifierOrTemplateInstance)
buildChainTemplateOrIdentifier(symbol, lookup, ctx, iot);
if(ue.unaryExpression)
traverseUnaryExpression(symbol, lookup, ctx, ue.unaryExpression);
}
override void visit(const VariableDeclaration dec) override void visit(const VariableDeclaration dec)
{ {
assert (currentSymbol); assert (currentSymbol);
foreach (declarator; dec.declarators) foreach (declarator; dec.declarators)
{ {
SemanticSymbol* symbol = allocateSemanticSymbol( SemanticSymbol* symbol = allocateSemanticSymbol(
@ -262,6 +492,29 @@ final class FirstPass : ASTVisitor
// TODO: remove this cast. See the note on structFieldTypes // TODO: remove this cast. See the note on structFieldTypes
structFieldTypes.insert(cast() dec.type); structFieldTypes.insert(cast() dec.type);
} }
auto lookup = symbol.typeLookups.front;
if (dec.type && dec.type.type2 && dec.type.type2.typeIdentifierPart)
{
TypeIdentifierPart typeIdentifierPart = cast(TypeIdentifierPart) dec.type.type2.typeIdentifierPart;
lookup.ctx.root = GCAllocator.instance.make!(VariableContext.TypeInstance)();
if (typeIdentifierPart.identifierOrTemplateInstance)
lookup.ctx.calltip = buildCalltip(typeIdentifierPart.identifierOrTemplateInstance.tokens);
foreach(suffix; dec.type.typeSuffixes)
{
if (suffix.type)
lookup.ctx.calltip ~= "[.]";
else if (suffix.array)
lookup.ctx.calltip ~= "[]";
else if (suffix.star != tok!"")
lookup.ctx.calltip ~= "*";
}
processTypeIdentifierPart(symbol, lookup, &lookup.ctx, lookup.ctx.root, typeIdentifierPart);
}
} }
if (dec.autoDeclaration !is null) if (dec.autoDeclaration !is null)
{ {
@ -284,6 +537,111 @@ final class FirstPass : ASTVisitor
// TODO: remove this cast. See the note on structFieldTypes // TODO: remove this cast. See the note on structFieldTypes
structFieldTypes.insert(null); structFieldTypes.insert(null);
} }
auto lookup = symbol.typeLookups.front;
istring[] original;
foreach(c; lookup.breadcrumbs[])
original ~= c;
writeln("## var: ", symbol.acSymbol.name);
writeln("## lookup breadcrumbs: ", lookup.breadcrumbs[]);
auto initializer = part.initializer.nonVoidInitializer;
if (initializer && initializer.assignExpression)
{
UnaryExpression unary = cast(UnaryExpression) initializer.assignExpression;
if (unary && (unary.newExpression || unary.indexExpression))
continue;
lookup.breadcrumbs.clear();
if (unary)
{
if (CastExpression castExpression = unary.castExpression)
{
if (castExpression.type && castExpression.type.type2)
{
Type2 t2 = castExpression.type.type2;
if (t2 && t2.typeIdentifierPart)
buildChain(symbol, lookup, &lookup.ctx, t2.typeIdentifierPart);
}
continue;
}
else if (FunctionCallExpression fc = unary.functionCallExpression)
unary = fc.unaryExpression;
// build chain
traverseUnaryExpression(symbol, lookup, &lookup.ctx, unary);
// needs to be reversed because it got added in order (right->left)
auto crumbs = &lookup.breadcrumbs;
istring[] result;
foreach(c; *crumbs)
result ~= c;
writeln("## result: ", result);
crumbs.clear();
foreach_reverse(c; result)
lookup.breadcrumbs.insert(c);
again:
// check template
if (IdentifierOrTemplateInstance iot = unary.identifierOrTemplateInstance)
{
if (iot.templateInstance)
{
lookup.ctx.root = GCAllocator.instance.make!(VariableContext.TypeInstance)();
processTemplateInstance(symbol, lookup, &lookup.ctx, lookup.ctx.root, iot.templateInstance);
}
else
{
writeln("something else2; ", iot.identifier.text, " original: ", original);
if (original.length > 0 && original[$-1] == "*arr*")
{
lookup.breadcrumbs.clear();
foreach(c; original)
lookup.breadcrumbs.insert(c);
foreach_reverse(c; result)
lookup.breadcrumbs.insert(c);
}
}
}
else if (PrimaryExpression pe = unary.primaryExpression)
{
if (pe.identifierOrTemplateInstance)
{
if (pe.identifierOrTemplateInstance.templateInstance)
{
lookup.ctx.root = GCAllocator.instance.make!(VariableContext.TypeInstance)();
processTemplateInstance(symbol, lookup, &lookup.ctx, lookup.ctx.root, pe.identifierOrTemplateInstance.templateInstance);
}
else
{
writeln("something else2; ", pe.identifierOrTemplateInstance.identifier.text);
}
}
else
{
writeln("something else other");
}
}
else
{
writeln("something else final");
if (unary.unaryExpression)
{
unary = unary.unaryExpression;
goto again;
}
else
{
foreach(c; original)
lookup.breadcrumbs.insert(c);
}
}
}
}
} }
} }
} }

View File

@ -35,6 +35,8 @@ import dparse.ast;
import dparse.lexer; import dparse.lexer;
import std.algorithm : filter; import std.algorithm : filter;
import std.range; import std.range;
import std.stdio;
import io = std.stdio;
void secondPass(SemanticSymbol* currentSymbol, Scope* moduleScope, ref ModuleCache cache) void secondPass(SemanticSymbol* currentSymbol, Scope* moduleScope, ref ModuleCache cache)
{ {
@ -57,6 +59,28 @@ void secondPass(SemanticSymbol* currentSymbol, Scope* moduleScope, ref ModuleCac
resolveType(currentSymbol.acSymbol, currentSymbol.typeLookups, resolveType(currentSymbol.acSymbol, currentSymbol.typeLookups,
moduleScope, cache); moduleScope, cache);
} }
if (currentSymbol.acSymbol.type && currentSymbol.typeLookups.length > 0)
{
foreach(lookup; currentSymbol.typeLookups[]) {
writeln("lookup: ", lookup.breadcrumbs[], " ctx: ", lookup.ctx.root);
if (lookup.ctx.root)
{
auto type = currentSymbol.acSymbol.type;
if (type.kind == structName || type.kind == className || type.kind == functionName || type.kind)
{
if (lookup.ctx.root.args.length > 0)
{
DSymbol*[string] mapping;
int depth;
resolveTemplate(currentSymbol.acSymbol, type, lookup, lookup.ctx.root, moduleScope, cache, depth, mapping);
break;
}
}
}
}
}
break; break;
case importSymbol: case importSymbol:
if (currentSymbol.acSymbol.type is null) if (currentSymbol.acSymbol.type is null)
@ -81,8 +105,22 @@ void secondPass(SemanticSymbol* currentSymbol, Scope* moduleScope, ref ModuleCac
break; break;
} }
// let's be methodic about the way we traverse symbols
// so that childs have access to resolved symbols
// functions should be last, because inside, there might be symbols that references
// code from the parent not yet resolved (templates)
foreach (child; currentSymbol.children) foreach (child; currentSymbol.children)
secondPass(child, moduleScope, cache); if (child.acSymbol.kind != CompletionKind.variableName && child.acSymbol.kind != CompletionKind.functionName)
secondPass(child, moduleScope, cache);
foreach (child; currentSymbol.children)
if (child.acSymbol.kind == CompletionKind.variableName)
secondPass(child, moduleScope, cache);
foreach (child; currentSymbol.children)
if (child.acSymbol.kind == CompletionKind.functionName)
secondPass(child, moduleScope, cache);
// Alias this and mixin templates are resolved after child nodes are // Alias this and mixin templates are resolved after child nodes are
// resolved so that the correct symbol information will be available. // resolved so that the correct symbol information will be available.
@ -100,6 +138,323 @@ void secondPass(SemanticSymbol* currentSymbol, Scope* moduleScope, ref ModuleCac
break; break;
} }
} }
/**
* Extract the return type from the callTip of a function symbol
*/
string extractReturnType(string callTip)
{
import std.string: indexOf;
auto spaceIndex = callTip.indexOf(" ");
if (spaceIndex <= 0) return "";
auto retPart = callTip[0 .. spaceIndex];
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(")")];
}
auto returnTypePtr = retPart[$-1] == '*';
auto returnTypeArr = retPart[$-1] == ']';
if (returnTypePtr)
{
retPart = retPart[0 .. $-1];
}
return retPart;
}
/**
* Copy a Type symbol with templates arguments
* Returns: Copy of Type symbol
*/
DSymbol* createTypeWithTemplateArgs(DSymbol* type, TypeLookup* lookup, VariableContext.TypeInstance* ti, ref ModuleCache cache, Scope* moduleScope, ref int depth, DSymbol*[string] m)
{
assert(type);
DSymbol* newType = GCAllocator.instance.make!DSymbol("dummy", CompletionKind.dummy, null);
newType.name = ti ? istring(ti.calltip) : istring(lookup.ctx.calltip);
// TODO: need to set the name in first.d
if (newType.name.length == 0)
newType.name = type.name;
print_tab(depth); io.write(">>", type.name, " > ", newType.name, " ::", ti," args: ", ti.args.length, " ct: ", ti.calltip);
writeln();
newType.kind = type.kind;
newType.qualifier = type.qualifier;
newType.protection = type.protection;
newType.symbolFile = type.symbolFile;
newType.doc = type.doc;
newType.type = type.type;
DSymbol*[string] mapping;
int count = 0;
if (ti.args.length > 0)
{
foreach(part; type.opSlice())
{
if (part.kind == CompletionKind.typeTmpParam)
{
scope(exit) count++;
if (count >= ti.args.length)
{
print_tab(depth);writeln("too many T for args available, investigate");
continue;
}
auto key = part.name;
print_tab(depth);writeln("> check template arg: ", key);
print_tab(depth);io.write("chain: ");
foreach(i, crumb; ti.args[count].chain)
{
io.write(crumb, ", ");
}
writeln("");
DSymbol* first;
bool isBuiltin;
foreach(i, crumb; ti.args[count].chain)
{
auto argName = crumb;
if (i == 0)
{
if (m && key in m)
{
argName = m[key].name;
}
// check if that's a built in type
// if it is, then use it and skip the type creation step
foreach(builtin; builtinSymbols)
{
if (builtin.name == crumb)
{
first = builtin;
isBuiltin = true;
break;
}
}
auto result = moduleScope.getSymbolsAtGlobalScope(istring(argName));
if (result.length == 0)
{
print_tab(depth);writeln("modulescope: symbol not found: ", argName);
break;
}
first = result[0];
print_tab(depth);writeln("modulescope: symbol found: ", argName, " -> ", first.name);
}
else
{
first = first.getFirstPartNamed(istring(argName));
if (first)
{
print_tab(depth);writeln("symbol found: ", argName, " -> ", first.name);
}
else
{
print_tab(depth);writeln("symbol not found: ", argName);
}
}
}
if (first is null)
continue;
print_tab(depth);writeln(">> ok");
auto ca = ti.args[count];
if (ca.chain.length > 0)
{
int indepth = depth + 1;
auto stomap = isBuiltin ? first : createTypeWithTemplateArgs(first, lookup, ca, cache, moduleScope, indepth, null);
mapping[key] = stomap;
print_tab(depth);writeln("mapping[",key,"] -> ", stomap.name, " builtin: ", isBuiltin);
}
}
else
{
//writeln(">>>>>>>>>>>>>>> what: ", part.kind," ", part.name);
}
}
}
// HACK: to support functions with template arguments that return a generic type
// first.d in processParameters only store the function's return type in the callTip
// maybe it's time to properly handle it by creating a proper symbol, so we can have
// proper support for functions that return complex types such as templates
if (type.kind == CompletionKind.functionName)
{
auto callTip = type.callTip;
if (callTip && callTip.length > 1)
{
auto retType = extractReturnType(callTip);
if (retType in mapping)
{
auto result = mapping[retType];
newType.ownType = result.kind == CompletionKind.keyword ? false : true;
newType.type = result;
}
}
}
writeln("-");
assert(newType);
string[] T_names;
foreach(part; type.opSlice())
{
if (part.kind == CompletionKind.typeTmpParam)
{
T_names ~= part.name;
}
else
if (part.type && part.type.kind == CompletionKind.typeTmpParam)
{
print_tab(depth); writeln("part: ", part.name,": ", part.type.name);
DSymbol* newPart = GCAllocator.instance.make!DSymbol(part.name, part.kind, null);
newPart.qualifier = part.qualifier;
newPart.protection = part.protection;
newPart.symbolFile = part.symbolFile;
newPart.doc = part.doc;
newPart.callTip = part.callTip;
if (part.type.name in mapping)
{
auto result = mapping[part.type.name];
newPart.ownType = result.kind == CompletionKind.keyword ? false : true;
newPart.type = result;
}
else if (m && part.type.name in m)
{
auto result = m[part.type.name];
newPart.ownType = result.kind == CompletionKind.keyword ? false : true;
newPart.type = result;
}
newType.addChild(newPart, true);
}
else if (part.type && part.type.name == "*arr*" && part.type.type && part.type.type.kind == CompletionKind.typeTmpParam)
{
auto arrSymbol = part.type;
auto arrTypeTSymbol = arrSymbol.type;
print_tab(depth); writeln("array: ", part.name,": ", arrTypeTSymbol.name,"[]");
DSymbol* newPart = GCAllocator.instance.make!DSymbol(part.name, part.kind, null);
newPart.qualifier = part.qualifier;
newPart.protection = part.protection;
newPart.symbolFile = part.symbolFile;
newPart.doc = part.doc;
newPart.callTip = part.callTip;
// create new array shit
if (arrTypeTSymbol.name in mapping)
{
auto result = mapping[arrTypeTSymbol.name];
print_tab(depth); writeln(" ", arrTypeTSymbol.name, " =>: ", result.name);
auto newarr = GCAllocator.instance.make!DSymbol(arrSymbol.name , arrSymbol.kind, result);
newarr.ownType = false;
newPart.type = newarr;
newPart.ownType = true;
}
newType.addChild(newPart, false);
}
else
{
print_tab(depth); writeln("missing part: ", part.name,": ", part.type);
// BUG: doing it recursively messes with the mapping
// i need to debug this and figure out perhaps a better way to do this stuff
// maybe move the VariableContext to the symbol directly
// i'll need to experiemnt with it
//DSymbol* part_T;
//if (depth < 50)
//if (part.type && part.kind == CompletionKind.variableName)
//foreach(partPart; part.type.opSlice())
//{
// if (partPart.kind == CompletionKind.typeTmpParam)
// {
// part_T = part;
// foreach(arg; ti.args)
// {
// warning(" > ", arg.chain);
// foreach(aa; arg.args)
// warning(" > ", aa.chain);
// }
// int indepth = depth;
// warning("go agane ", part.name, " ", part.type.name, " with arg: ", ti.chain," Ts: ", T_names);
// resolveTemplate(part, part.type, lookup, ti, moduleScope, cache, indepth, mapping);
// break;
// }
// //else if (partPart.type && partPart.type.kind == CompletionKind.typeTmpParam)
// //{
// // warning("here!".red," ", partPart.name," ", partPart.type.name);
// //}
//}
newType.addChild(part, false);
}
}
return newType;
}
void print_tab(int index)
{
enum C = 4;
for(int i =0; i < index*4; i++) io.write(" ");
}
/**
* Resolve template arguments
*/
void resolveTemplate(DSymbol* variableSym, DSymbol* type, TypeLookup* lookup, VariableContext.TypeInstance* current, Scope* moduleScope, ref ModuleCache cache, ref int depth, DSymbol*[string] mapping = null)
{
depth += 1;
if (variableSym is null || type is null) return;
if (current.chain.length == 0) return; // TODO: should not be empty, happens for simple stuff Inner inner; TODO: i forgot why, add a test
writeln("> Resolve template for: ",variableSym.name, ": ", type.name);
writeln("ctx callTip: ", lookup.ctx.calltip);
void printti(VariableContext.TypeInstance* it, ref int index)
{
print_tab(index); io.write("chain:", it.chain, "name: ", it.name, " ct: ", it.calltip, " args: ", it.args.length, "\n");
index += 1;
foreach(itt; it.args)
{
int inindex = index;
printti(itt, inindex);
}
}
int index = 0;
printti(lookup.ctx.root, index);
writeln("");
writeln("");
DSymbol* newType = createTypeWithTemplateArgs(type, lookup, current, cache, moduleScope, depth, mapping);
writeln("");
writeln("resolved:", variableSym.name, " > ", newType.name);
if (depth == 1)
{
newType.name = istring(lookup.ctx.calltip);
}
variableSym.type = newType;
variableSym.ownType = true;
}
void resolveImport(DSymbol* acSymbol, ref TypeLookups typeLookups, void resolveImport(DSymbol* acSymbol, ref TypeLookups typeLookups,
ref ModuleCache cache) ref ModuleCache cache)
@ -281,10 +636,12 @@ do
if (lastSuffix !is null) if (lastSuffix !is null)
{ {
assert(suffix !is null); assert(suffix !is null);
typeSwap(currentSymbol);
suffix.type = currentSymbol; suffix.type = currentSymbol;
suffix.ownType = false; suffix.ownType = false;
symbol.type = lastSuffix; symbol.type = lastSuffix;
symbol.ownType = true; symbol.ownType = true;
if (currentSymbol is null && !remainingImports.empty) if (currentSymbol is null && !remainingImports.empty)
{ {
// info("Deferring type resolution for ", symbol.name); // info("Deferring type resolution for ", symbol.name);
@ -320,6 +677,9 @@ void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup,
size_t i = 0; size_t i = 0;
auto crumbs = lookup.breadcrumbs[]; auto crumbs = lookup.breadcrumbs[];
writeln(">> crumbs: ", crumbs);
writeln(">> name: ", symbol.name);
foreach (crumb; crumbs) foreach (crumb; crumbs)
{ {
if (i == 0) if (i == 0)
@ -328,7 +688,10 @@ void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup,
symbolNameToTypeName(crumb), symbol.location); symbolNameToTypeName(crumb), symbol.location);
if (currentSymbol is null) if (currentSymbol is null)
{
writeln("return 0");
return; return;
}
} }
else if (crumb == ARRAY_LITERAL_SYMBOL_NAME) else if (crumb == ARRAY_LITERAL_SYMBOL_NAME)
{ {
@ -340,7 +703,10 @@ void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup,
{ {
typeSwap(currentSymbol); typeSwap(currentSymbol);
if (currentSymbol is null) if (currentSymbol is null)
{
writeln("return");
return; return;
}
// Index expressions can be on a pointer, an array or an AA // Index expressions can be on a pointer, an array or an AA
if (currentSymbol.qualifier == SymbolQualifier.array if (currentSymbol.qualifier == SymbolQualifier.array
@ -349,9 +715,15 @@ void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup,
|| currentSymbol.kind == CompletionKind.aliasName) || currentSymbol.kind == CompletionKind.aliasName)
{ {
if (currentSymbol.type !is null) if (currentSymbol.type !is null)
{
writeln("here! ", currentSymbol.type.name);
currentSymbol = currentSymbol.type; currentSymbol = currentSymbol.type;
}
else else
{
writeln("nope!");
return; return;
}
} }
else else
{ {
@ -359,7 +731,11 @@ void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup,
if (opIndex !is null) if (opIndex !is null)
currentSymbol = opIndex.type; currentSymbol = opIndex.type;
else else
return; {
writeln("return weird");
writeln("s: ", currentSymbol.name, " ", currentSymbol.qualifier);
continue;
}
} }
} }
else if (crumb == "foreach") else if (crumb == "foreach")
@ -388,18 +764,29 @@ void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup,
} }
else else
{ {
writeln("here");
typeSwap(currentSymbol); typeSwap(currentSymbol);
if (currentSymbol is null) if (currentSymbol is null)
{
writeln("return", i);
return; return;
}
currentSymbol = currentSymbol.getFirstPartNamed(crumb); currentSymbol = currentSymbol.getFirstPartNamed(crumb);
} }
++i; ++i;
if (currentSymbol is null) if (currentSymbol is null)
{
writeln("return end", i);
return; return;
}
} }
typeSwap(currentSymbol); typeSwap(currentSymbol);
symbol.type = currentSymbol; symbol.type = currentSymbol;
symbol.ownType = false; symbol.ownType = false;
if (currentSymbol)
writeln(">> type: ", currentSymbol.name);
} }
private: private:

View File

@ -199,7 +199,7 @@ unittest
}; };
ScopeSymbolPair pair = generateAutocompleteTrees(source, cache); ScopeSymbolPair pair = generateAutocompleteTrees(source, cache);
DSymbol* meaningOfLife = pair.symbol.getFirstPartNamed(istring("meaningOfLife")); DSymbol* meaningOfLife = pair.symbol.getFirstPartNamed(istring("meaningOfLife"));
assert(meaningOfLife.type.name == "*arr*"); assert(meaningOfLife.type.name == "int[]");
} }

View File

@ -37,4 +37,19 @@ struct TypeLookup
UnrolledList!istring breadcrumbs; UnrolledList!istring breadcrumbs;
/// The kind of type lookup /// The kind of type lookup
TypeLookupKind kind; TypeLookupKind kind;
/// To store information about template instances
VariableContext ctx;
}
struct VariableContext
{
struct TypeInstance
{
string[] chain;
TypeInstance*[] args;
string name;
string calltip;
}
TypeInstance* root;
string calltip;
} }

View File

@ -8,7 +8,7 @@
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
":dsymbol": "*", ":dsymbol": "*",
"libdparse": ">=0.23.0 <0.24.0", "libdparse": ">=0.23.2 <0.24.0",
":common": "*", ":common": "*",
"emsi_containers": "~>0.9.0" "emsi_containers": "~>0.9.0"
}, },

View File

@ -3,7 +3,7 @@
"versions": { "versions": {
"dsymbol": "0.14.1", "dsymbol": "0.14.1",
"emsi_containers": "0.9.0", "emsi_containers": "0.9.0",
"libdparse": "0.23.0", "libdparse": "0.23.2",
"msgpack-d": "1.0.4", "msgpack-d": "1.0.4",
"stdx-allocator": "2.77.5" "stdx-allocator": "2.77.5"
} }

@ -1 +1 @@
Subproject commit 86c9bf44c96e1666eb175c749cc26f62c2008979 Subproject commit 10658375b22f284e2fcb44074a862c213309cfb3

View File

@ -1,7 +1,6 @@
identifiers identifiers
C h
alignof k alignof k
i v i v int i stdin 21 int
init k init k
mangleof k mangleof k
sizeof k sizeof k

View File

@ -1,5 +1,5 @@
set -e set -e
set -u set -u
../../bin/dcd-client $1 file.d -c66 > actual1.txt ../../bin/dcd-client $1 file.d --extended -c66 > actual1.txt
diff actual1.txt expected1.txt --strip-trailing-cr diff actual1.txt expected1.txt --strip-trailing-cr

View File

@ -1,2 +1,2 @@
identifiers identifiers
bar v foo bar stdin 92 bar v stdin 92

View File

@ -0,0 +1,94 @@
struct Data
{
int inside_data;
Inner inner;
}
struct Inner
{
int inside_inner;
}
struct AganeOne(T)
{
int inside_aganeone;
T yo;
}
struct AganeTwo(T, U)
{
int inside_aganetwo;
T yo_T;
U yo_U;
}
struct Other(T)
{
int inside_other;
T what;
AganeOne!(T) agane_T;
AganeOne!(Inner) agane_inner;
}
struct One(T){ T inside_one; }
struct Outter {
struct Two(T, U){ int inside_two; T agane_one; U agane_two; One!(T) one_agane_one; T get_T(T)(){return T.init;} U get_U(){return U.init;} }
}
struct A{ int inside_a;}
struct B{ int inside_b;}
struct C{ int inside_c;}
struct What
{
int inside_what;
const(V) get_it(T, U, V)() { return T.init; }
}
void main()
{
auto from_auto = Outter.Two!(
AganeOne!(Other!(Data)),
AganeTwo!(A, B)
)();
Outter.Two!(
AganeOne!(Other!(Data)),
AganeTwo!(A, Other!(B))
) from_normal;
auto u = from_auto.get_U();
auto uuu = from_normal.agane_two;
auto v = from_normal.get_U();
What what;
auto it = what.get_it!(A, B, C)();
{
from_auto.agane_one.
}
{
from_auto.agane_two.
}
{
from_normal.agane_two.
}
{
from_normal.agane_two.
}
{
u.
}
{
uuu.
}
{
uuu.
}
{
it.
}
}

View File

@ -0,0 +1,9 @@
identifiers
alignof k
init k
mangleof k
one_t v One!T one_t stdin 103 One!T
sizeof k
stringof k
tupleof k
value_t v A value_t stdin 0 A

View File

@ -0,0 +1,9 @@
identifiers
alignof k
init k
mangleof k
sizeof k
stringof k
tupleof k
value_t v A value_t stdin 0 A
value_u v B value_u stdin 0 B

View File

@ -0,0 +1,9 @@
identifiers
alignof k
init k
mangleof k
one_t v One!T one_t stdin 103 One!T
sizeof k
stringof k
tupleof k
value_t v A value_t stdin 0 A

View File

@ -0,0 +1,9 @@
identifiers
alignof k
init k
mangleof k
sizeof k
stringof k
tupleof k
value_t v A value_t stdin 0 A
value_u v B value_u stdin 0 B

View File

@ -0,0 +1,9 @@
identifiers
alignof k
init k
mangleof k
sizeof k
stringof k
tupleof k
value_key v int value_key stdin 0 int
value_value v int value_value stdin 0 int

View File

@ -0,0 +1,9 @@
identifiers
alignof k
init k
mangleof k
sizeof k
stringof k
tupleof k
value_key v int value_key stdin 0 int
value_value v int value_value stdin 0 int

View File

@ -0,0 +1,9 @@
identifiers
alignof k
init k
mangleof k
sizeof k
stringof k
tupleof k
value_key v int value_key stdin 0 int
value_value v int value_value stdin 0 int

View File

@ -0,0 +1,9 @@
identifiers
alignof k
init k
mangleof k
sizeof k
stringof k
tupleof k
value_key v int value_key stdin 0 int
value_value v int value_value stdin 0 int

View File

@ -0,0 +1,8 @@
identifiers
alignof k
init k int
mangleof k
max k int
min k int
sizeof k
stringof k

View File

@ -0,0 +1,9 @@
identifiers
alignof k
init k
inside_aganeone v int inside_aganeone stdin 124 int
mangleof k
sizeof k
stringof k
tupleof k
yo v Other yo stdin 0 Other

View File

@ -0,0 +1,10 @@
identifiers
alignof k
init k
inside_aganetwo v int inside_aganetwo stdin 186 int
mangleof k
sizeof k
stringof k
tupleof k
yo_T v A yo_T stdin 0 A
yo_U v B yo_U stdin 0 B

View File

@ -0,0 +1,10 @@
identifiers
alignof k
init k
inside_aganetwo v int inside_aganetwo stdin 186 int
mangleof k
sizeof k
stringof k
tupleof k
yo_T v A yo_T stdin 0 A
yo_U v Other yo_U stdin 0 Other

View File

@ -0,0 +1,10 @@
identifiers
alignof k
init k
inside_aganetwo v int inside_aganetwo stdin 186 int
mangleof k
sizeof k
stringof k
tupleof k
yo_T v A yo_T stdin 0 A
yo_U v Other yo_U stdin 0 Other

View File

@ -0,0 +1,10 @@
identifiers
alignof k
init k
inside_aganetwo v int inside_aganetwo stdin 186 int
mangleof k
sizeof k
stringof k
tupleof k
yo_T v A yo_T stdin 0 A
yo_U v B yo_U stdin 0 B

View File

@ -0,0 +1,10 @@
identifiers
alignof k
init k
inside_aganetwo v int inside_aganetwo stdin 186 int
mangleof k
sizeof k
stringof k
tupleof k
yo_T v A yo_T stdin 0 A
yo_U v Other yo_U stdin 0 Other

View File

@ -0,0 +1,10 @@
identifiers
alignof k
init k
inside_aganetwo v int inside_aganetwo stdin 186 int
mangleof k
sizeof k
stringof k
tupleof k
yo_T v A yo_T stdin 0 A
yo_U v Other yo_U stdin 0 Other

View File

@ -0,0 +1,8 @@
identifiers
alignof k
init k
inside_c v int inside_c stdin 605 int
mangleof k
sizeof k
stringof k
tupleof k

View File

@ -0,0 +1,2 @@
identifiers
read_test f void read_test() stdin 38 void

View File

@ -0,0 +1,31 @@
struct A
{
int inside_a;
}
struct B
{
int inside_b;
}
struct One(T)
{
T value_t;
One!T one_t;
}
struct Two(T, U)
{
T value_t;
U value_u;
}
void main()
{
auto from_auto_one = One!(A)();
auto from_auto_two = Two!(A, B)();
{
from_auto_one.
}
{
from_auto_two.
}
}

View File

@ -0,0 +1,31 @@
struct A
{
int inside_a;
}
struct B
{
int inside_b;
}
struct One(T)
{
T value_t;
One!T one_t;
}
struct Two(T, U)
{
T value_t;
U value_u;
}
void main()
{
One!A from_normal_one;
Two!(A, B) from_normal_two;
{
from_normal_one.
}
{
from_normal_two.
}
}

View File

@ -0,0 +1,49 @@
struct TopHashMap(Key, Value)
{
Key value_key;
Value value_value;
}
void main()
{
auto top = TopHashMap!(int, int)();
auto bottom = BottomHashMap!(int, int)();
{
top.
}
{
auto copy = top;
copy.
}
{
bottom.
}
{
auto copy = bottom;
copy.
}
{
auto wf = WithFunction!(int, int)();
auto gkey = wf.get_key();
gkey.
}
}
struct BottomHashMap(Key, Value)
{
Key value_key;
Value value_value;
}
struct WithFunction(Key, Value)
{
Key get_key()
{
return Key.init;
}
Value get_value()
{
return Value.init;
}
}

View File

@ -0,0 +1,12 @@
struct ReaderTest(bool LE)
{
void read_test(){}
}
alias ReaderTestBE = ReaderTest!true;
struct Test
{
void read(ReaderTestBE* reader)
{
reader.re
}
}

View File

@ -0,0 +1,63 @@
#!/bin/bash
set -e
set -u
MODE=$1
function check () {
echo ":: :: check: $1 $2 $3"
../../bin/dcd-client.exe $MODE $1.d --extended -c $2 > $3.txt
diff $3.txt $4.txt --strip-trailing-cr
}
#echo "extra"
check file4 165 actual_extra_1 expected_extra_1
#echo "test1"
check file1 282 actual_1_1 expected_1_1
#echo "test2"
check file1 317 actual_1_2 expected_1_2
#echo "test3"
check file2 268 actual_2_1 expected_2_1
#echo "test4"
check file2 305 actual_2_2 expected_2_2
#echo "test5"
check file3 195 actual_3_1 expected_3_1
#echo "test6"
check file3 246 actual_3_2 expected_3_2
#echo "test7"
check file3 274 actual_3_3 expected_3_3
#echo "test8"
check file3 328 actual_3_4 expected_3_4
#echo "test9"
check file3 433 actual_3_5 expected_3_5
#echo "test complex"
check complex 1121 actual_complex_1 expected_complex_1
check complex 1162 actual_complex_2 expected_complex_2
check complex 1205 actual_complex_3 expected_complex_3
check complex 1248 actual_complex_4 expected_complex_4
check complex 1271 actual_complex_5 expected_complex_5
check complex 1296 actual_complex_6 expected_complex_6
check complex 1321 actual_complex_7 expected_complex_7
check complex 1345 actual_complex_8 expected_complex_8