save progress

This commit is contained in:
ryuukk 2023-02-11 19:26:44 +01:00
parent 220dcb0445
commit f34407ce31
11 changed files with 1969 additions and 1408 deletions

View File

@ -232,9 +232,127 @@ final class FirstPass : ASTVisitor
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 processTemplateInstance(SemanticSymbol* symbol, TypeLookup* lookup, VariableContext* ctx, VariableContext.TypeInstance* current, TemplateInstance ti)
{
if (ti.identifier != tok!"")
{
current.chain ~= ti.identifier.text;
warning("type: ", ti.identifier.text);
}
else assert(0, "templateinstance type missing");
if (ti.templateArguments)
{
if (ti.templateArguments.templateArgumentList)
{
foreach(i, targ; ti.templateArguments.templateArgumentList.items)
{
if (targ.type is null) continue;
if (targ.type.type2 is null) continue;
auto part = targ.type.type2.typeIdentifierPart;
auto newArg = GCAllocator.instance.make!(VariableContext.TypeInstance)();
newArg.parent = current;
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);
}
}
}
}
else if (ti.templateArguments.templateSingleArgument)
{
auto singleArg = ti.templateArguments.templateSingleArgument;
symbol.acSymbol.tmplArgNames ~= istring(singleArg.token.text);
auto arg = GCAllocator.instance.make!(VariableContext.TypeInstance)();
arg.parent = current;
arg.name = singleArg.token.text;
arg.chain ~= arg.name;
current.args ~= arg;
}
}
}
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);
}
void buildChainTemplateOrIdentifier(SemanticSymbol* symbol, TypeLookup* lookup, VariableContext* ctx, IdentifierOrTemplateInstance iot)
{
auto crumb = iot.identifier;
if (crumb != tok!"")
{
warning(" c: ", crumb.text);
lookup.breadcrumbs.insert(istring(crumb.text));
}
if (iot.templateInstance)
{
if (iot.templateInstance.identifier != tok!"")
lookup.breadcrumbs.insert(istring(iot.templateInstance.identifier.text));
}
}
void traverseUnaryExpression( SemanticSymbol* symbol, TypeLookup* lookup, VariableContext* ctx, UnaryExpression ue)
{
warning("traverse unary");
if (PrimaryExpression pe = ue.primaryExpression)
{
warning("primary expression");
if (pe.identifierOrTemplateInstance)
{
buildChainTemplateOrIdentifier(symbol, lookup, ctx, pe.identifierOrTemplateInstance);
}
}
if (IdentifierOrTemplateInstance iot = ue.identifierOrTemplateInstance)
{
warning("has iot");
auto crumb = iot.identifier;
if (crumb != tok!"")
{
warning(": ", crumb.text);
lookup.breadcrumbs.insert(istring(crumb.text));
}
}
if(ue.unaryExpression) traverseUnaryExpression(symbol, lookup, ctx, ue.unaryExpression);
}
override void visit(const VariableDeclaration dec)
{
assert (currentSymbol);
warning("current: ", currentSymbol.acSymbol.name);
foreach (declarator; dec.declarators)
{
SemanticSymbol* symbol = allocateSemanticSymbol(
@ -262,14 +380,35 @@ final class FirstPass : ASTVisitor
typeIdentifierPart.identifierOrTemplateInstance.templateInstance)
{
auto templateInstance = typeIdentifierPart.identifierOrTemplateInstance.templateInstance;
if (templateInstance.templateArguments.templateArgumentList)
// if template
// allocate symbol
// set kind to TypeArg
// set index
// for each argument
// create child symbol
// set kind to TypeArg
// set index
// to resolve:
// get item.type
// copy symbol
// traverse and replace parts
if (!templateInstance.templateArguments)
{}
else if (templateInstance.templateArguments.templateArgumentList)
{
foreach(i, targ; templateInstance.templateArguments.templateArgumentList.items)
{
if (targ.type is null) continue;
// TODO: support template with multiple arguments
auto tokens = targ.type.type2.tokens;
warning(" tokens: ", tokens[0].text);
}
}
else if (typeIdentifierPart.identifierOrTemplateInstance.templateInstance.templateArguments.templateSingleArgument)
else if (templateInstance.templateArguments.templateSingleArgument)
{
auto singleArg = typeIdentifierPart.identifierOrTemplateInstance.templateInstance.templateArguments.templateSingleArgument;
symbol.acSymbol.tmplArgNames ~= istring(singleArg.token.text);
@ -279,11 +418,13 @@ final class FirstPass : ASTVisitor
}
if (dec.autoDeclaration !is null)
{
warning("is auto!");
foreach (part; dec.autoDeclaration.parts)
{
SemanticSymbol* symbol = allocateSemanticSymbol(
part.identifier.text, CompletionKind.variableName,
symbolFile, part.identifier.index);
symbol.acSymbol.isAutoDeclaration = true;
symbol.parent = currentSymbol;
populateInitializer(symbol, part.initializer);
symbol.acSymbol.protection = protection.current;
@ -291,6 +432,80 @@ final class FirstPass : ASTVisitor
currentSymbol.addChild(symbol, true);
currentScope.addSymbol(symbol.acSymbol, false);
warning(" part: ", symbol.acSymbol.name);
scope(exit) warning("crumbs: ", symbol.typeLookups.front.breadcrumbs[]);
// for auto declaration, we'll properly traverse the initializer
// and set the proper crumbs instead of using just the first one
// so we can handle things like cast/templates
auto lookup = symbol.typeLookups.front;
lookup.breadcrumbs.clear();
auto initializer = part.initializer.nonVoidInitializer;
if (initializer && initializer.assignExpression)
{
UnaryExpression unary = cast(UnaryExpression) initializer.assignExpression;
if (unary)
{
if (CastExpression castExpression = unary.castExpression)
{
warning("cast expression");
if (castExpression.type && castExpression.type.type2)
{
Type2 t2 = castExpression.type.type2;
if (t2 && t2.typeIdentifierPart)
{
buildChain(symbol, lookup, &lookup.ctx, t2.typeIdentifierPart);
}
}
}
else if (FunctionCallExpression fc = unary.functionCallExpression)
{
warning("functioncall expression ", fc.type, " ", fc.unaryExpression," ", fc.templateArguments);
}
}
if (unary)
{
// 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;
}
crumbs.clear();
foreach_reverse(c; result)
{
lookup.breadcrumbs.insert(c);
}
// check template
if (IdentifierOrTemplateInstance iot = unary.identifierOrTemplateInstance)
{
auto crumb = iot.identifier;
if (crumb != tok!"")
{
lookup.breadcrumbs.insert(istring(crumb.text));
}
else if (iot.templateInstance)
{
auto tic = iot.templateInstance.identifier;
warning("template! ", tic.text);
lookup.breadcrumbs.insert(istring(tic.text));
lookup.ctx.root = GCAllocator.instance.make!(VariableContext.TypeInstance)();
assert(lookup.ctx.root != null);
processTemplateInstance(symbol, lookup, &lookup.ctx, lookup.ctx.root, iot.templateInstance);
}
}
}
}
if (currentSymbol.acSymbol.kind == CompletionKind.structName
|| currentSymbol.acSymbol.kind == CompletionKind.unionName)
{

View File

@ -55,6 +55,25 @@ void secondPass(SemanticSymbol* currentSymbol, Scope* moduleScope, ref ModuleCac
resolveType(currentSymbol.acSymbol, currentSymbol.typeLookups,
moduleScope, cache);
}
if (currentSymbol.acSymbol.type && currentSymbol.typeLookups.length > 0)
{
TypeLookup* lookup = currentSymbol.typeLookups.front;
if (lookup.ctx.root)
{
auto type = currentSymbol.acSymbol.type;
if (type.kind == structName || type.kind == className)
{
int depth;
resolveTemplate(currentSymbol.acSymbol, type, lookup, lookup.ctx.root, moduleScope, cache, depth);
}
}
}
else
{
warning("no type: ", currentSymbol.acSymbol.name," ", currentSymbol.acSymbol.kind);
}
break;
case importSymbol:
if (currentSymbol.acSymbol.type is null)
@ -76,6 +95,7 @@ void secondPass(SemanticSymbol* currentSymbol, Scope* moduleScope, ref ModuleCac
case dummy:
case templateName:
case mixinTemplateName:
case argTmpParam:
break;
}
@ -94,40 +114,15 @@ void secondPass(SemanticSymbol* currentSymbol, Scope* moduleScope, ref ModuleCac
resolveMixinTemplates(currentSymbol.acSymbol, currentSymbol.typeLookups,
moduleScope, cache);
break;
case variableName:
case functionName:
if (currentSymbol.acSymbol.tmplArgNames.length > 0 && currentSymbol.acSymbol.type)
{
auto tArgNames = currentSymbol.acSymbol.tmplArgNames;
auto type = currentSymbol.acSymbol.type;
if (type.kind == structName || type.kind == className)
{
int depth;
resolveTemplate(currentSymbol.acSymbol, type, tArgNames, moduleScope, cache, depth);
}
}
else
{
warning("no type: ", currentSymbol.acSymbol.name," ", currentSymbol.acSymbol.kind);
}
break;
default:
break;
}
}
/**
* Resolve template arguments
*/
void resolveTemplate(DSymbol* sym, DSymbol* type, scope const istring[] tmplArgNames, Scope* moduleScope, ref ModuleCache cache, ref int depth)
DSymbol* createTypeWithTemplateArgs(DSymbol* type, TypeLookup* lookup, VariableContext.TypeInstance* ti, ref ModuleCache cache, Scope* moduleScope, ref int depth, DSymbol*[string] m = null)
{
depth += 1;
if (tmplArgNames.length > 1) return;
auto argName = tmplArgNames[0];
auto result = moduleScope.getSymbolsAtGlobalScope(argName);
if (result.length > 0)
{
auto argSymbol = result[0];
warning("processing type: ", type.name, " ", ti.chain, " ", ti.args);
DSymbol* newType = GCAllocator.instance.make!DSymbol("", CompletionKind.dummy, null);
newType.name = type.name;
newType.kind = type.kind;
@ -136,51 +131,145 @@ void resolveTemplate(DSymbol* sym, DSymbol* type, scope const istring[] tmplArgN
newType.symbolFile = type.symbolFile;
newType.doc = type.doc;
newType.callTip = type.callTip;
DSymbol*[string] mapping;
DSymbol* currentT = null;
if (m)
foreach(k,v; m)
{
mapping[k] = v;
}
int[string] mapping_index;
int count = 0;
if (ti.args.length > 0)
{
warning("hard args, build mapping");
foreach(part; type.opSlice())
{
if (part.kind == CompletionKind.typeTmpParam)
{
currentT = part;
scope(exit) count++;
warning("building mapping for: ", part.name, " chain: ", ti.args[count].chain);
auto key = part.name;
DSymbol* first;
foreach(i, crumb; ti.args[count].chain)
{
if (i == 0)
{
auto result = moduleScope.getSymbolsAtGlobalScope(istring(crumb));
if (result.length == 0)
{
error("can't find symbol: ", crumb);
break;
}
first = result[0];
}
else {
first = first.getFirstPartNamed(istring(crumb));
}
}
mapping_index[key] = count;
if (first is null)
{
error("can't find type for mapping: ", part.name);
continue;
}
warning(" map: ", key ,"->", first.name);
mapping[key] = createTypeWithTemplateArgs(first, lookup, ti.args[count], cache, moduleScope, depth, m ? m : mapping);
}
}
}
string[] T_names;
foreach(part; type.opSlice())
{
if (part.kind == CompletionKind.typeTmpParam)
{
warning(" #", count, " ", part.name);
T_names ~= part.name;
}
else if (part.type && part.type.kind == CompletionKind.typeTmpParam)
{
DSymbol* newPart = GCAllocator.instance.make!DSymbol(part.name, part.kind, argSymbol);
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;
newPart.type = argSymbol;
if (part.kind == CompletionKind.functionName)
newPart.ownType = true;
if (part.type.name in mapping)
{
if (part.type && part.type.kind == CompletionKind.typeTmpParam)
newPart.type = mapping[part.type.name];
warning(" mapping found: ", part.type.name," -> ", newPart.type.name);
}
else
if (m && part.type.name in m)
{
newPart.type = argSymbol;
}
newPart.type = m[part.type.name];
warning(" mapping found: ", part.type.name," -> ", newPart.type.name);
}
else
error(" mapping not found: ", part.type.name);
newType.addChild(newPart, true);
}
else
{
if (part.tmplArgNames.length > 0)
{
auto innerArg = part.tmplArgNames[0];
if (innerArg == currentT.name)
{
if (depth < 50)
resolveTemplate(part, part.type, [argName], moduleScope, cache, depth);
if (part.type && part.kind == CompletionKind.variableName)
foreach(partPart; part.type.opSlice())
{
if (partPart.kind == CompletionKind.typeTmpParam)
{
warning("go agane ", part.name, " ", part.type.name, " with arg: ", ti.chain," Ts: ", T_names);
foreach(arg; ti.args)
{
warning(" >", arg.chain, " ", arg.args);
}
//resolveTemplate(part, part.type, lookup, ti, moduleScope, cache, depth, mapping);
break;
}
}
newType.addChild(part, false);
newType.addChild(part, true);
}
}
sym.type = newType;
sym.ownType = true;
}
return newType;
}
/**
* 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;
warning("resolving template for var: ", variableSym.name, " type: ", type.name, "depth: ", depth);
warning("current args: ");
foreach(i, arg; current.args)
warning(" i: ", i, " ", arg.chain);
DSymbol* newType = createTypeWithTemplateArgs(type, lookup, current, cache, moduleScope, depth, mapping);
variableSym.type = newType;
variableSym.ownType = true;
}
void resolveImport(DSymbol* acSymbol, ref TypeLookups typeLookups,
ref ModuleCache cache)
in
@ -521,13 +610,17 @@ void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup,
auto crumbs = lookup.breadcrumbs[];
foreach (crumb; crumbs)
{
warning("search: ", crumb);
if (i == 0)
{
currentSymbol = moduleScope.getFirstSymbolByNameAndCursor(
symbolNameToTypeName(crumb), symbol.location);
if (currentSymbol is null)
{
warning("return 0");
return;
}
}
else
if (crumb == ARRAY_LITERAL_SYMBOL_NAME)
@ -589,13 +682,19 @@ void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup,
{
typeSwap(currentSymbol);
if (currentSymbol is null )
{
warning("return ", i);
return;
}
currentSymbol = currentSymbol.getFirstPartNamed(crumb);
}
++i;
if (currentSymbol is null)
{
warning("return ", i);
return;
}
}
typeSwap(currentSymbol);
symbol.type = currentSymbol;
symbol.ownType = false;

View File

@ -104,6 +104,9 @@ enum CompletionKind : char
/// type template parameter when no constraint
typeTmpParam = 'h',
/// type template argument when no constraint
argTmpParam = 'H',
}
/**
@ -386,6 +389,11 @@ struct DSymbol
*/
istring[] tmplArgNames;
/**
* Template arguments symbols
*/
DSymbol*[] tmplArgs;
/**
* Function parameter symbols
*/
@ -431,7 +439,8 @@ struct DSymbol
mixin(bitfields!(bool, "ownType", 1,
bool, "skipOver", 1,
bool, "isPointer", 1,
ubyte, "", 5));
bool, "isAutoDeclaration", 1,
ubyte, "", 4));
// dfmt on
/// Protection level for this symbol

View File

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

View File

@ -0,0 +1,2 @@
identifiers
yo v Inner yo stdin 0

View File

@ -0,0 +1,3 @@
identifiers
yo_T v A yo_T stdin 0
yo_U v B yo_U stdin 0

View File

View File

@ -0,0 +1,55 @@
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; }
}
struct A{ int inside_a;}
struct B{ int inside_b;}
void main()
{
auto from_auto = Outter.Two!(
AganeOne!(Other!(Data)),
AganeTwo!(A, B)
);
import std;
writeln(typeid(from_auto.agane_one.yo.agane_inner.yo));
}

View File

@ -0,0 +1,47 @@
struct Data
{
float inside_data;
Inner inner;
}
struct Inner
{
float inside_inner;
}
struct AganeOne(T)
{
T yo;
}
struct AganeTwo(T, U)
{
T yo_T;
U yo_U;
}
struct Other(T)
{
T what;
AganeOne!(T) agane_T;
AganeOne!(Inner) agane_inner;
}
struct One(T){ T inside_one; }
struct Outter {
struct Two(T, U){ T agane_one; U agane_two; One!(T) one_agane_one; }
}
struct A{ int inside_a;}
struct B{ int inside_b;}
void main()
{
auto from_auto = Outter.Two!(
AganeOne!(Other!Data),
AganeTwo!(A, B)
);
from_auto.agane_two.yo
}

105
tests/tc_templates/file3.d Normal file
View File

@ -0,0 +1,105 @@
struct Data
{
float inside_data;
Inner inner;
}
struct Inner
{
float inside_inner;
}
struct AganeOne(T)
{
T yo;
}
struct AganeTwo(T, U)
{
T yo_T;
U yo_U;
}
struct Other(T)
{
T what;
AganeOne!(T) agane_T;
AganeOne!(Inner) agane_inner;
}
struct MyTemplate(T)
{
T T_value;
Other!(T) other;
T get_this_value(T)()
{
return T_value;
}
}
struct Fat
{
struct Outter
{
struct Inner(T)
{
T from_inner_T;
}
int from_outter;
}
struct Other
{
int from_other;
}
struct Agane
{
int from_agane;
}
int from_fat;
}
struct One(T){ T inside_one; }
struct Outter {
struct Two(T, U){ T agane_one; U agane_two; One!(T) one_agane_one; }
}
struct A{ int inside_a;}
struct B{ int inside_b;}
void main()
{
auto from_auto = Outter.Two!(
AganeOne!(Other!Data),
AganeTwo!(A, B)
);
// import std;
from_auto.agane_one.yo.agane_inner.y;
//writeln(typeid(from_auto.agane_one.yo.agane_inner));
//writeln(typeid(from_auto.agane_one.yo.agane_T));
//writeln(typeid(from_auto.agane_one.yo.what));
}
/**
Inner(IdentifierOrTemplateInstance)
[One, Two]
[Fat, Outter] [A, B]
*/

10
tests/tc_templates/run.sh Normal file
View File

@ -0,0 +1,10 @@
set -e
set -u
../../bin/dcd-client $1 file1.d --extended -c 688 > actual_1.txt
diff actual_1.txt expected_1.txt --strip-trailing-cr
../../bin/dcd-client $1 file2.d --extended -c 674 > actual_2.txt
diff actual_2.txt expected_2.txt --strip-trailing-cr