1 module dvardumper.dumper;
2 
3 import std.stdio : write;
4 import dvardumper.typevar;
5 import std.outbuffer : OutBuffer;
6 import std.array : empty;
7 
8 void dump(T)(Dumper d, T var, string varname = "")
9 {
10     d.doDump(var.toTypeVar(varname), DumpOptions())
11      .write();
12 }
13 
14 interface Dumper
15 {
16     string doDump(TypeVar, DumpOptions);
17 }
18 
19 struct DumpOptions
20 {
21     bool showSize = false;
22 }
23 
24 class VarDumper : Dumper
25 {
26     private:
27         OutBuffer buffer;
28         string indentString = "  ";
29 
30     public:
31         this()
32         {
33             buffer = new OutBuffer();
34         }
35 
36         string doDump(TypeVar var, DumpOptions dumpOptions)
37         {
38             buffer.clear();
39             buffer.writefln("%s", "---------------");
40 
41             dumpInternal(var, 0, dumpOptions);
42 
43             buffer.writefln("%s", "===============");
44 
45             return buffer.toString();
46         }
47 
48     protected:
49         string formatVarName(string name)
50         {
51             if (name != "") {
52                 return `"` ~ name ~ `"`;
53             }
54 
55             return "";
56         }
57 
58         void dumpInternal(TypeVar var, ushort level, DumpOptions dumpOptions)
59         {
60             if (auto v = cast(BasicTypeVar)var) {
61                 dumpBasicTypeVar(v, level, dumpOptions);
62             } else if (auto v = cast(PointerTypeVar)var) {
63                 dumpPointerTypeVar(v, level, dumpOptions);
64             } else if (auto v = cast(ArrayTypeVar)var) {
65                 dumpArrayTypeVar(v, level, dumpOptions);
66             } else if (auto v = cast(AggregateTypeVar)var) {
67                 dumpAggregateTypeVar(v, level, dumpOptions);
68             } else if (auto v = cast(UnknownTypeVar)var) {
69                 dumpUnknownTypeVar(v, level);
70             } else {
71                 assert(0, "Can't determine TypeVar instance");
72             }
73         }
74 
75         void dumpBasicTypeVar(BasicTypeVar v, ushort level, DumpOptions dumpOptions)
76         {
77             writeIndent(level);
78             buffer.writef("%s", v.typeName);
79             if (dumpOptions.showSize) {
80                 buffer.writef("(%d)", v.size);
81             }
82 
83             buffer.writefln(" %s = %s", v.name, v.value);
84         }
85 
86         void dumpPointerTypeVar(PointerTypeVar v, ushort level, DumpOptions dumpOptions)
87         {
88             writeIndent(level);
89             buffer.writef("%s", v.typeName);
90             if (dumpOptions.showSize) {
91                 buffer.writef("(%d)", v.size);
92             }
93             buffer.writefln(" %s = %#x", v.name, v.pointer);
94         }
95 
96         void dumpArrayTypeVar(ArrayTypeVar v, ushort level, DumpOptions dumpOptions)
97         {
98             writeIndent(level);
99             string typeName = v.typeName;
100 
101             auto aliasMap = [
102                 typeid(string).toString() : string.stringof,
103                 typeid(dstring).toString() : dstring.stringof,
104                 typeid(wstring).toString() : wstring.stringof
105             ];
106 
107             if (typeName in aliasMap) {
108                 typeName = aliasMap[typeName];
109             }
110 
111             buffer.writef("%s", typeName);
112             if (dumpOptions.showSize) {
113                 buffer.writef("(%d)", v.size);
114             }
115             buffer.writef(" %s[%d*%d]", v.name, v.elementCount, v.elementSize);
116 
117             if (v.isPrintable) {
118                 if (v.elementCount > v.maxPrintCount) {
119                     string value = cast(string)v.array[0..v.elementSize * v.maxPrintCount];
120                     buffer.writefln(` = "%s ..."`, value);
121                 } else {
122                     buffer.writefln(` = "%s"`, cast(string)v.array);
123                 }
124             } else {
125                 buffer.writefln(": <%d bytes of data>", v.elementCount * v.elementSize);
126             }
127         }
128 
129         void dumpAggregateTypeVar(AggregateTypeVar v, ushort level, DumpOptions dumpOptions)
130         {
131             writeIndent(level);
132             buffer.writef("%s", v.typeName);
133             if (dumpOptions.showSize) {
134                 buffer.writef("(%d)", v.size);
135             }
136 
137             if (!v.name.empty) {
138                 buffer.writefln(" %s {", v.name);
139             } else {
140                 buffer.writefln(" {");
141             }
142 
143             foreach (TypeVar field; v.fields) {
144                 dumpInternal(field, cast(ushort)(level+1), dumpOptions);
145             }
146 
147             writeIndent(level);
148             buffer.writefln("}");
149         }
150 
151         void dumpUnknownTypeVar(UnknownTypeVar v, ushort level)
152         {
153             writeIndent(level);
154             buffer.writefln("%s(%d) %s: (unknown type var)", v.typeName, v.size, v.name);
155         }
156 
157         void writeIndent(ushort level = 0)
158         {
159             import std.array : replicate;
160 
161             buffer.write(indentString.replicate(level));
162         }
163 }