save progress

This commit is contained in:
ryuukk 2023-02-13 03:21:56 +01:00
parent f34407ce31
commit 388ec2f1cd
5 changed files with 799 additions and 194 deletions

View File

@ -0,0 +1,533 @@
module dsymbol.coloredlogger;
import std.logger;
import std.stdio;
import std.concurrency;
import std.datetime;
import std.stdio;
import std.algorithm : map, filter, joiner;
import std.array : join, split;
import std.conv : to;
import std.format : format;
import std.functional : not;
import std.range : ElementType, empty, front, popFront;
import std.regex : ctRegex, Captures, replaceAll;
import std.string : toUpper;
import std.traits : EnumMembers;
version (unittest)
{
import core.thread : Thread;
import core.time : msecs;
import std.conv : to;
import std.process : environment;
import std.stdio : writeln, write;
import unit_threaded;
}
/// Available Colors
enum AnsiColor
{
black = 30,
red = 31,
green = 32,
yellow = 33,
blue = 34,
magenta = 35,
cyan = 36,
lightGray = 37,
defaultColor = 39,
darkGray = 90,
lightRed = 91,
lightGreen = 92,
lightYellow = 93,
lightBlue = 94,
lightMagenta = 95,
lightCyan = 96,
white = 97
}
/// Available Styles
enum Style
{
bold = 1,
dim = 2,
underlined = 4,
blink = 5,
reverse = 7,
hidden = 8
}
/// Internal structure to style a string
struct StyledString
{
private string unformatted;
private int[] befores;
private int[] afters;
/// Create a styled string
public this(string unformatted)
{
this.unformatted = unformatted;
}
private StyledString addPair(int before, int after)
{
befores ~= before;
afters ~= after;
return this;
}
StyledString setForeground(int color)
{
return addPair(color, 0);
}
StyledString setBackground(int color)
{
return addPair(color + 10, 0);
}
/// Add styling to a string
StyledString addStyle(int style)
{
return addPair(style, 0);
}
string toString() const @safe
{
auto prefix = befores.map!(a => "\033[%dm".format(a)).join("");
auto suffix = afters.map!(a => "\033[%dm".format(a)).join("");
return "%s%s%s".format(prefix, unformatted, suffix);
}
/// Concatenate with another string
string opBinary(string op : "~")(string rhs) @safe
{
return toString ~ rhs;
}
}
/// Truecolor string
struct RGBString
{
private string unformatted;
/// Colorinformation
struct RGB
{
/// Red component 0..256
ubyte r;
/// Green component 0..256
ubyte g;
/// Blue component 0..256
ubyte b;
}
private RGB* foreground;
private RGB* background;
/// Create RGB String
this(string unformatted)
{
this.unformatted = unformatted;
}
/// Set color
auto rgb(ubyte r, ubyte g, ubyte b)
{
this.foreground = new RGB(r, g, b);
return this;
}
/// Set background color
auto onRgb(ubyte r, ubyte g, ubyte b)
{
this.background = new RGB(r, g, b);
return this;
}
string toString() @safe
{
auto res = "";
if (foreground != null)
{
res = "\033[38;2;%s;%s;%sm".format(foreground.r, foreground.g, foreground.b) ~ res;
}
if (background != null)
{
res = "\033[48;2;%s;%s;%sm".format(background.r, background.g, background.b) ~ res;
}
res ~= unformatted;
if (foreground != null || background != null)
{
res ~= "\033[0m";
}
return res;
}
}
/// Convinient helper function
string rgb(string s, ubyte r, ubyte g, ubyte b)
{
return RGBString(s).rgb(r, g, b).toString;
}
/// Convinient helper function
string onRgb(string s, ubyte r, ubyte g, ubyte b)
{
return RGBString(s).onRgb(r, g, b).toString;
}
@system @("rgb") unittest
{
import std.experimental.color : RGBA8, convertColor;
import std.experimental.color.hsx : HSV;
writeln("red: ", "r".rgb(255, 0, 0).onRgb(0, 255, 0));
writeln("green: ", "g".rgb(0, 255, 0).onRgb(0, 0, 255));
writeln("blue: ", "b".rgb(0, 0, 255).onRgb(255, 0, 0));
writeln("mixed: ", ("withoutColor" ~ "red".red.to!string ~ "withoutColor").bold);
for (int r = 0; r <= 255; r += 10)
{
for (int g = 0; g <= 255; g += 3)
{
write(" ".onRgb(cast(ubyte) r, cast(ubyte) g, cast(ubyte)(255 - r)));
}
writeln;
}
int delay = environment.get("DELAY", "0").to!int;
for (int j = 0; j < 255; j += 1)
{
for (int i = 0; i < 255; i += 3)
{
auto c = HSV!ubyte(cast(ubyte)(i - j), 0xff, 0xff);
auto rgb = convertColor!RGBA8(c).tristimulus;
write(" ".onRgb(rgb[0].value, rgb[1].value, rgb[2].value));
}
Thread.sleep(delay.msecs);
write("\r");
}
writeln;
}
@system @("styledstring") unittest
{
foreach (immutable color; [EnumMembers!AnsiColor])
{
auto colorName = "%s".format(color);
writeln(StyledString(colorName).setForeground(color));
}
foreach (immutable color; [EnumMembers!AnsiColor])
{
auto colorName = "bg%s".format(color);
writeln(StyledString(colorName).setBackground(color));
}
foreach (immutable style; [EnumMembers!Style])
{
auto styleName = "%s".format(style);
writeln(StyledString(styleName).addStyle(style));
}
writeln("boldUnderlined".bold.underlined);
writeln("redOnGreenReverse".red.onGreen.reverse);
}
@system @("styledstring ~") unittest
{
("test".red ~ "blub").should == "\033[31mtest\033[0mblub";
}
/// Create `color` and `onColor` functions for all enum members. e.g. "abc".green.onRed
auto colorMixin(T)()
{
string res = "";
foreach (immutable color; [EnumMembers!T])
{
auto t = typeof(T.init).stringof;
auto c = "%s".format(color);
res ~= "auto %1$s(string s) { return StyledString(s).setForeground(%2$s.%1$s); }\n".format(c,
t);
res ~= "auto %1$s(StyledString s) { return s.setForeground(%2$s.%1$s); }\n".format(c, t);
string name = c[0 .. 1].toUpper ~ c[1 .. $];
res ~= "auto on%3$s(string s) { return StyledString(s).setBackground(%2$s.%1$s); }\n".format(c,
t, name);
res ~= "auto on%3$s(StyledString s) { return s.setBackground(%2$s.%1$s); }\n".format(c,
t, name);
}
return res;
}
/// Create `style` functions for all enum mebers, e.g. "abc".bold
auto styleMixin(T)()
{
string res = "";
foreach (immutable style; [EnumMembers!T])
{
auto t = typeof(T.init).stringof;
auto s = "%s".format(style);
res ~= "auto %1$s(string s) { return StyledString(s).addStyle(%2$s.%1$s); }\n".format(s, t);
res ~= "auto %1$s(StyledString s) { return s.addStyle(%2$s.%1$s); }\n".format(s, t);
}
return res;
}
mixin(colorMixin!AnsiColor);
mixin(styleMixin!Style);
@system @("api") unittest
{
"redOnGreen".red.onGreen.writeln;
"redOnYellowBoldUnderlined".red.onYellow.bold.underlined.writeln;
"bold".bold.writeln;
"test".writeln;
}
/// Calculate length of string excluding all formatting escapes
ulong unformattedLength(string s)
{
enum State
{
NORMAL,
ESCAPED,
}
auto state = State.NORMAL;
ulong count = 0;
foreach (c; s)
{
switch (state)
{
case State.NORMAL:
if (c == 0x1b)
{
state = State.ESCAPED;
}
else
{
count++;
}
break;
case State.ESCAPED:
if (c == 'm')
{
state = State.NORMAL;
}
break;
default:
throw new Exception("Illegal state");
}
}
return count;
}
/++ Range to work with ansi escapes. The ESC[ parts and m must be
+ already removed and the numbers need to be converted to uints.
+ See https://en.wikipedia.org/wiki/ANSI_escape_code
+/
auto tokenize(Range)(Range parts)
{
struct TokenizeResult(Range)
{
Range parts;
ElementType!(Range)[] next;
this(Range parts)
{
this.parts = parts;
tokenizeNext();
}
private void tokenizeNext()
{
next = [];
if (parts.empty)
{
return;
}
switch (parts.front)
{
case 38:
case 48:
next ~= 38;
parts.popFront;
switch (parts.front)
{
case 2:
next ~= 2;
parts.popFront;
next ~= parts.front;
parts.popFront;
next ~= parts.front;
parts.popFront;
next ~= parts.front;
parts.popFront;
break;
case 5:
next ~= 5;
parts.popFront;
next ~= parts.front;
parts.popFront;
break;
default:
throw new Exception("Only [38,48];[2,5] are supported but got %s;%s".format(next[0],
parts.front));
}
break;
case 0: .. case 37:
case 39: .. case 47:
case 49:
case 51:
.. case 55:
case 60: .. case 65:
case 90: .. case 97:
case 100: .. case 107:
next ~= parts.front;
parts.popFront;
break;
default:
throw new Exception("Only colors are supported");
}
}
auto front()
{
return next;
}
bool empty()
{
return next == null;
}
void popFront()
{
tokenizeNext();
}
}
return TokenizeResult!(Range)(parts);
}
@system @("ansi tokenizer") unittest
{
[38, 5, 2, 38, 2, 1, 2, 3, 36, 1, 2, 3, 4].tokenize.should == ([
[38, 5, 2], [38, 2, 1, 2, 3], [36], [1], [2], [3], [4]
]);
}
/++ Remove classes of ansi escapes from a styled string.
+/
string filterAnsiEscapes(alias predicate)(string s)
{
string withFilters(Captures!string c)
{
auto parts = c[1].split(";").map!(a => a.to!uint)
.tokenize
.filter!(p => predicate(p));
if (parts.empty)
{
return "";
}
else
{
return "\033[" ~ parts.joiner.map!(a => "%d".format(a)).join(";") ~ "m";
}
}
alias r = ctRegex!"\033\\[(.*?)m";
return s.replaceAll!(withFilters)(r);
}
/// Predicate to select foreground color ansi escapes
bool foregroundColor(uint[] token)
{
return token[0] >= 30 && token[0] <= 38;
}
/// Predicate to select background color ansi escapes
bool backgroundColor(uint[] token)
{
return token[0] >= 40 && token[0] <= 48;
}
/// Predicate to select style ansi escapes
bool style(uint[] token)
{
return token[0] >= 1 && token[0] <= 29;
}
/// Predicate select nothing
bool none(uint[])
{
return false;
}
/// Predicate to select all
bool all(uint[])
{
return true;
}
@system @("configurable strip") unittest
{
import unit_threaded;
import std.functional : not;
"test".red.onGreen.bold.toString.filterAnsiEscapes!(foregroundColor).should == "\033[31mtest";
"test".red.onGreen.bold.toString.filterAnsiEscapes!(not!foregroundColor)
.should == "\033[42m\033[1mtest\033[0m\033[0m\033[0m";
"test".red.onGreen.bold.toString.filterAnsiEscapes!(style).should == "\033[1mtest";
"test".red.onGreen.bold.toString.filterAnsiEscapes!(none).should == "test";
"test".red.onGreen.bold.toString.filterAnsiEscapes!(all)
.should == "\033[31m\033[42m\033[1mtest\033[0m\033[0m\033[0m";
"test".red.onGreen.bold.toString.filterAnsiEscapes!(backgroundColor).should == "\033[42mtest";
}
/// Add fillChar to the right of the string until width is reached
auto leftJustifyFormattedString(string s, ulong width, dchar fillChar = ' ')
{
auto res = s;
const currentWidth = s.unformattedLength;
for (long i = currentWidth; i < width; ++i)
{
res ~= fillChar;
}
return res;
}
@system @("leftJustifyFormattedString") unittest
{
import unit_threaded;
"test".red.toString.leftJustifyFormattedString(10).should == "\033[31mtest\033[0m ";
}
/// Add fillChar to the left of the string until width is reached
auto rightJustifyFormattedString(string s, ulong width, char fillChar = ' ')
{
auto res = s;
const currentWidth = s.unformattedLength;
for (long i = currentWidth; i < width; ++i)
{
res = fillChar ~ res;
}
return res;
}
@system @("rightJustifyFormattedString") unittest
{
"test".red.toString.rightJustifyFormattedString(10).should == (" \033[31mtest\033[0m");
}
/// Force a style on possible preformatted text
auto forceStyle(string text, Style style) {
return "\033[%d".format(style.to!int) ~ "m" ~ text.split("\033[0m").join("\033[0;%d".format(style.to!int) ~"m") ~ "\033[0m";
}
@("forceStyle") unittest
{
auto splitt = "1es2eses3".split("es").filter!(not!(empty));
splitt.should == ["1", "2", "3"];
string s = "noformatting%snoformatting".format("red".red).forceStyle(Style.reverse);
writeln(s);
s.should == "\033[7mnoformatting\033[31mred\033[0;7mnoformatting\033[0m";
}

View File

@ -245,6 +245,24 @@ final class FirstPass : ASTVisitor
}
}
void processTypeIdentifierPart(SemanticSymbol* symbol, TypeLookup* lookup, VariableContext* ctx, VariableContext.TypeInstance* current, TypeIdentifierPart tip)
{
auto newArg = GCAllocator.instance.make!(VariableContext.TypeInstance)();
newArg.parent = current;
current.args ~= newArg;
if (tip.identifierOrTemplateInstance)
{
processIdentifierOrTemplate(symbol, lookup, ctx, newArg, tip.identifierOrTemplateInstance);
}
if (tip.typeIdentifierPart)
{
error("i should probably handle this");
}
}
void processTemplateInstance(SemanticSymbol* symbol, TypeLookup* lookup, VariableContext* ctx, VariableContext.TypeInstance* current, TemplateInstance ti)
{
if (ti.identifier != tok!"")
@ -264,6 +282,8 @@ final class FirstPass : ASTVisitor
if (targ.type.type2 is null) continue;
auto part = targ.type.type2.typeIdentifierPart;
if (part is null) continue;
auto newArg = GCAllocator.instance.make!(VariableContext.TypeInstance)();
newArg.parent = current;
current.args ~= newArg;
@ -278,6 +298,11 @@ final class FirstPass : ASTVisitor
{
processIdentifierOrTemplate(symbol, lookup, ctx, newArg, part.typeIdentifierPart.identifierOrTemplateInstance);
}
if (part.typeIdentifierPart)
{
error("i should probably handle this");
}
}
}
}
@ -373,47 +398,15 @@ final class FirstPass : ASTVisitor
// TODO: remove this cast. See the note on structFieldTypes
structFieldTypes.insert(cast() dec.type);
}
if (dec.type.type2 && dec.type.type2.typeIdentifierPart)
auto lookup = symbol.typeLookups.front;
if (dec.type && dec.type.type2 && dec.type.type2.typeIdentifierPart)
{
auto typeIdentifierPart = dec.type.type2.typeIdentifierPart;
if (typeIdentifierPart && typeIdentifierPart.identifierOrTemplateInstance &&
typeIdentifierPart.identifierOrTemplateInstance.templateInstance)
{
auto templateInstance = typeIdentifierPart.identifierOrTemplateInstance.templateInstance;
TypeIdentifierPart typeIdentifierPart = cast(TypeIdentifierPart) dec.type.type2.typeIdentifierPart;
// 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 (templateInstance.templateArguments.templateSingleArgument)
{
auto singleArg = typeIdentifierPart.identifierOrTemplateInstance.templateInstance.templateArguments.templateSingleArgument;
symbol.acSymbol.tmplArgNames ~= istring(singleArg.token.text);
}
}
lookup.ctx.root = GCAllocator.instance.make!(VariableContext.TypeInstance)();
processTypeIdentifierPart(symbol, lookup, &lookup.ctx, lookup.ctx.root, typeIdentifierPart);
}
}
if (dec.autoDeclaration !is null)
@ -462,6 +455,9 @@ final class FirstPass : ASTVisitor
else if (FunctionCallExpression fc = unary.functionCallExpression)
{
warning("functioncall expression ", fc.type, " ", fc.unaryExpression," ", fc.templateArguments);
//if (fc.unaryExpression)
// traverseUnaryExpression(symbol, lookup, &lookup.ctx, unary);
unary = fc.unaryExpression;
}
}
@ -498,7 +494,6 @@ final class FirstPass : ASTVisitor
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);
}
}

View File

@ -50,7 +50,7 @@ ScopeSymbolPair generateAutocompleteTrees(const(Token)[] tokens,
secondPass(first.rootSymbol, first.moduleScope, cache);
thirdPass(first.moduleScope, cache, cursorPosition);
thirdPass(first.rootSymbol, first.moduleScope, cache, cursorPosition);
auto r = move(first.rootSymbol.acSymbol);
typeid(SemanticSymbol).destroy(first.rootSymbol);

View File

@ -28,6 +28,7 @@ import dsymbol.type_lookup;
import dsymbol.deferred;
import dsymbol.import_;
import dsymbol.modulecache;
import dsymbol.coloredlogger;
import std.experimental.allocator;
import std.experimental.allocator.gc_allocator : GCAllocator;
import std.experimental.logger;
@ -62,10 +63,11 @@ void secondPass(SemanticSymbol* currentSymbol, Scope* moduleScope, ref ModuleCac
if (lookup.ctx.root)
{
auto type = currentSymbol.acSymbol.type;
if (type.kind == structName || type.kind == className)
if (type.kind == structName || type.kind == className && lookup.ctx.root.args.length > 0)
{
int depth;
resolveTemplate(currentSymbol.acSymbol, type, lookup, lookup.ctx.root, moduleScope, cache, depth);
//DSymbol*[string] mapping;
//int depth;
//resolveTemplate(currentSymbol.acSymbol, type, lookup, lookup.ctx.root, moduleScope, cache, depth, mapping);
}
}
}
@ -120,155 +122,6 @@ void secondPass(SemanticSymbol* currentSymbol, Scope* moduleScope, ref ModuleCac
}
DSymbol* createTypeWithTemplateArgs(DSymbol* type, TypeLookup* lookup, VariableContext.TypeInstance* ti, ref ModuleCache cache, Scope* moduleScope, ref int depth, DSymbol*[string] m = null)
{
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;
newType.qualifier = type.qualifier;
newType.protection = type.protection;
newType.symbolFile = type.symbolFile;
newType.doc = type.doc;
newType.callTip = type.callTip;
DSymbol*[string] mapping;
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)
{
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, null);
newPart.qualifier = part.qualifier;
newPart.protection = part.protection;
newPart.symbolFile = part.symbolFile;
newPart.doc = part.doc;
newPart.callTip = part.callTip;
newPart.ownType = true;
if (part.type.name in mapping)
{
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 = 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 (depth < 50)
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, 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)

View File

@ -24,8 +24,13 @@ import dsymbol.semantic;
import dsymbol.symbol;
import dsymbol.string_interning;
import dsymbol.deferred;
import dsymbol.type_lookup;
import containers.hashset;
import dsymbol.coloredlogger;
import std.logger;
import std.experimental.allocator;
import std.experimental.allocator.gc_allocator;
/**
@ -34,12 +39,231 @@ import containers.hashset;
* If it is, then it'll set its type
* If the symbol is not found, then it'll do nothing
*/
void thirdPass(Scope* mscope, ref ModuleCache cache, size_t cursorPosition)
void thirdPass(SemanticSymbol* symbol, Scope* mscope, ref ModuleCache cache, size_t cursorPosition)
{
auto desired = mscope.getScopeByCursor(cursorPosition);
tryResolve(desired, cache);
// now as our final step, let's try to resolve templates
tryResolveTemplates(symbol, mscope, cache);
}
void tryResolveTemplates(SemanticSymbol* currentSymbol, Scope* mscope, ref ModuleCache cache)
{
with (CompletionKind) switch (currentSymbol.acSymbol.kind)
{
case variableName:
case memberVariableName:
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 && lookup.ctx.root.args.length > 0)
{
DSymbol*[string] mapping;
int depth;
resolveTemplate(currentSymbol.acSymbol, type, lookup, lookup.ctx.root, mscope, cache, depth, mapping);
}
}
}
else
{
warning("no type: ", currentSymbol.acSymbol.name," ", currentSymbol.acSymbol.kind);
}
break;
default: break;
}
foreach (child; currentSymbol.children)
tryResolveTemplates(child, mscope, cache);
}
DSymbol* createTypeWithTemplateArgs(DSymbol* type, TypeLookup* lookup, VariableContext.TypeInstance* ti, ref ModuleCache cache, Scope* moduleScope, ref int depth, DSymbol*[string] m)
{
assert(type);
warning("processing type: ", type.name, " ", ti.chain, " ", ti.args);
DSymbol* newType = GCAllocator.instance.make!DSymbol("dummy", CompletionKind.dummy, null);
newType.name = type.name;
newType.kind = type.kind;
newType.qualifier = type.qualifier;
newType.protection = type.protection;
newType.symbolFile = type.symbolFile;
newType.doc = type.doc;
newType.callTip = type.callTip;
newType.type = type.type;
DSymbol*[string] mapping;
if (m)
foreach(k,v; m)
{
warning("store mapping: ".yellow, k, " ", v.name);
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)
{
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)
{
auto argName = crumb;
if (i == 0)
{
if (key in mapping)
{
//first = mapping[argName];
//continue;
argName = mapping[key].name;
}
auto result = moduleScope.getSymbolsAtGlobalScope(istring(argName));
if (result.length == 0)
{
error("can't find symbol: ".red, argName);
foreach(k, v; mapping)
{
warning("k: ", k, " v: ", v);
}
break;
}
first = result[0];
}
else {
first = first.getFirstPartNamed(istring(argName));
}
}
mapping_index[key] = count;
if (first is null)
{
error("can't find type for mapping: ".red, part.name);
continue;
}
warning(" map: ", key ,"->", first.name);
warning(" creating type: ".blue, first.name);
auto ca = ti.args[count];
if (ca.chain.length > 0)
mapping[key] = createTypeWithTemplateArgs(first, lookup, ca, cache, moduleScope, depth, mapping);
}
}
}
assert(newType);
warning("process parts..");
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, null);
newPart.qualifier = part.qualifier;
newPart.protection = part.protection;
newPart.symbolFile = part.symbolFile;
newPart.doc = part.doc;
newPart.callTip = part.callTip;
newPart.ownType = false;
if (part.type.name in mapping)
{
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 = m[part.type.name];
warning(" mapping in m found: ", part.type.name," -> ", newPart.type.name);
}
else
error(" mapping not found: ".red, part.type.name," type: ", type.name, " cur: ", ti.chain, "args: ", ti.args);
newType.addChild(newPart, true);
}
else
{
//if (depth < 50)
//if (part.type && part.kind == CompletionKind.variableName)
//foreach(partPart; part.type.opSlice())
//{
// if (partPart.kind == CompletionKind.typeTmpParam)
// {
// foreach(arg; ti.args)
// {
// warning(" >", arg.chain, " ", arg.args);
// }
// warning("go agane ".blue, part.name, " ", part.type.name, " with arg: ", ti.chain," Ts: ", T_names);
// //resolveTemplate(part, part.type, lookup, ti, moduleScope, cache, depth, mapping);
// break;
// }
//}
warning("adding untouched: ", part.name, "into: ", newType);
newType.addChild(part, false);
}
}
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;
if (variableSym is null || type is null) return;
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);
warning("current chain: ", current.chain, " name: ", current.name);
if (current.chain.length == 0) return; // TODO: should not be empty, happens for simple stuff Inner inner;
DSymbol* newType = createTypeWithTemplateArgs(type, lookup, current, cache, moduleScope, depth, mapping);
variableSym.type = newType;
variableSym.ownType = true;
}
/**
* Used to resolve missing symbols within a scope
*/