save progress

This commit is contained in:
ryuukk 2023-02-13 15:43:55 +01:00
parent 1c54fc9873
commit f8332b50f8
11 changed files with 1230 additions and 0 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

@ -231,10 +231,151 @@ final class FirstPass : ASTVisitor
currentSymbol.addChild(symbol, true);
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)
{
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!"")
{
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;
if (part is null) continue;
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);
}
if (part.typeIdentifierPart)
{
error("i should probably handle this");
}
}
}
}
else if (ti.templateArguments.templateSingleArgument)
{
auto singleArg = ti.templateArguments.templateSingleArgument;
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(
@ -255,9 +396,20 @@ final class FirstPass : ASTVisitor
// TODO: remove this cast. See the note on structFieldTypes
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)();
processTypeIdentifierPart(symbol, lookup, &lookup.ctx, lookup.ctx.root, typeIdentifierPart);
}
}
if (dec.autoDeclaration !is null)
{
warning("is auto!");
foreach (part; dec.autoDeclaration.parts)
{
SemanticSymbol* symbol = allocateSemanticSymbol(
@ -270,6 +422,81 @@ 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 (fc.unaryExpression)
// traverseUnaryExpression(symbol, lookup, &lookup.ctx, unary);
unary = fc.unaryExpression;
}
}
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)();
processTemplateInstance(symbol, lookup, &lookup.ctx, lookup.ctx.root, iot.templateInstance);
}
}
}
}
if (currentSymbol.acSymbol.kind == CompletionKind.structName
|| currentSymbol.acSymbol.kind == CompletionKind.unionName)
{

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;
@ -55,6 +56,24 @@ 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 && lookup.ctx.root.args.length > 0)
{
DSymbol*[string] mapping;
int depth;
resolveTemplate(currentSymbol.acSymbol, type, lookup, lookup.ctx.root, moduleScope, cache, depth, mapping);
}
}
}
else
{
warning("no type: ", currentSymbol.acSymbol.name," ", currentSymbol.acSymbol.kind);
}
break;
case importSymbol:
if (currentSymbol.acSymbol.type is null)
@ -99,6 +118,175 @@ 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)
{
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;
}
void resolveImport(DSymbol* acSymbol, ref TypeLookups typeLookups,
ref ModuleCache cache)
in

View File

@ -37,4 +37,19 @@ 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
inside_inner v int inside_inner 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

@ -0,0 +1,96 @@
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;}
void main()
{
auto from_auto = Outter.Two!(
AganeOne!(Other!(Data)),
AganeTwo!(A, B)
)();
auto check = from_auto;
import std;
// should be of type Inner, completion: inside_inner
writeln(typeid(from_auto.agane_one)); //file1.AganeOne!(file1.Other!(file1.Data).Other).AganeOne
writeln(typeid(from_auto.agane_one.yo)); // file1.Other!(file1.Data).Other
writeln(typeid(from_auto.agane_one.yo.agane_inner)); // file1.AganeOne!(file1.Inner).AganeOne
writeln(typeid(from_auto.agane_one.yo.agane_inner.yo)); // file1.Inner
}
// struct S { int x; int y; }
// S doStuff(int x) { return S(); }
// void main(string[] args)
// {
// auto alpha = 10;
// auto bravo = S(1, 2);
// int charlie = 4;
// auto delta = doStuff();
// {
// alpha
// }
// {
// bravo.
// }
// {
// charlie.
// }
// {
// delta.
// }
// }

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
}

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]
*/

View File

@ -0,0 +1,14 @@
set -e
set -u
../../bin/dcd-client $1 file1.d --extended -c 831
#echo "test1"
#../../bin/dcd-client $1 file1.d --extended -c 751 > actual_1.txt
#diff actual_1.txt expected_1.txt --strip-trailing-cr
#echo "test2"
#../../bin/dcd-client $1 file2.d --extended -c 674 > actual_2.txt
#diff actual_2.txt expected_2.txt --strip-trailing-cr