From 388ec2f1cde5bf3c42b6c049286b6bcd4a49431d Mon Sep 17 00:00:00 2001 From: ryuukk Date: Mon, 13 Feb 2023 03:21:56 +0100 Subject: [PATCH] save progress --- dsymbol/src/dsymbol/coloredlogger.d | 533 +++++++++++++++++++++++ dsymbol/src/dsymbol/conversion/first.d | 75 ++-- dsymbol/src/dsymbol/conversion/package.d | 2 +- dsymbol/src/dsymbol/conversion/second.d | 157 +------ dsymbol/src/dsymbol/conversion/third.d | 226 +++++++++- 5 files changed, 799 insertions(+), 194 deletions(-) create mode 100644 dsymbol/src/dsymbol/coloredlogger.d diff --git a/dsymbol/src/dsymbol/coloredlogger.d b/dsymbol/src/dsymbol/coloredlogger.d new file mode 100644 index 0000000..f4148f5 --- /dev/null +++ b/dsymbol/src/dsymbol/coloredlogger.d @@ -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"; +} diff --git a/dsymbol/src/dsymbol/conversion/first.d b/dsymbol/src/dsymbol/conversion/first.d index c6f85d4..a857fe4 100644 --- a/dsymbol/src/dsymbol/conversion/first.d +++ b/dsymbol/src/dsymbol/conversion/first.d @@ -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); } } diff --git a/dsymbol/src/dsymbol/conversion/package.d b/dsymbol/src/dsymbol/conversion/package.d index e145cdc..c512f81 100644 --- a/dsymbol/src/dsymbol/conversion/package.d +++ b/dsymbol/src/dsymbol/conversion/package.d @@ -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); diff --git a/dsymbol/src/dsymbol/conversion/second.d b/dsymbol/src/dsymbol/conversion/second.d index 93df50b..4131c22 100644 --- a/dsymbol/src/dsymbol/conversion/second.d +++ b/dsymbol/src/dsymbol/conversion/second.d @@ -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) diff --git a/dsymbol/src/dsymbol/conversion/third.d b/dsymbol/src/dsymbol/conversion/third.d index 88b7cd3..845bb51 100644 --- a/dsymbol/src/dsymbol/conversion/third.d +++ b/dsymbol/src/dsymbol/conversion/third.d @@ -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 */