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 }