1 module overloadgen; 2 import plugin; 3 import std.stdio; 4 import std.json; 5 import std.array : split; 6 import std.algorithm : countUntil; 7 import std.file : readText, exists; 8 9 bool willDefineOverloadTemplate = false; 10 11 static struct OverloadedFunction 12 { 13 string returnType; 14 string argsTypes; 15 string argsParams; 16 string cimguiFunc; 17 } 18 19 static struct Function 20 { 21 string owner; 22 string name; 23 bool exists; 24 bool willForward; 25 26 @property string fname() 27 { 28 if(owner == "") 29 return name; 30 else 31 return owner~"_"~name; 32 } 33 OverloadedFunction[] overloads; 34 } 35 36 string[] ignoreList = 37 [ 38 "ImVector_ImVector", 39 "ImVector_back", 40 "ImVector_begin", 41 "ImVector_end", 42 "ImVector_erase", 43 "ImVector_find", 44 "ImVector_front", 45 "ImVector_resize" 46 ]; 47 48 bool isOnIgnoreList(string line) 49 { 50 foreach(ignore;ignoreList) 51 if(line.countUntil(ignore) != -1) 52 return true; 53 return false; 54 } 55 56 bool hasVarArgs(string params) 57 { 58 return params.countUntil("...") != -1; 59 } 60 61 static Function[] getFunctions(File file) 62 { 63 Function[] ret; 64 ret.reserve(128); 65 66 Function func; 67 foreach(int i, string line; lines(file)) 68 { 69 int firstCharValue = line[0]; 70 if(firstCharValue == '-') 71 continue; 72 if(firstCharValue >= '0' && firstCharValue <= '9' && func.exists) 73 { 74 string[] infos = line.split(); 75 if(infos[1] == "overloaded") 76 return ret~= func; 77 else 78 { 79 OverloadedFunction overload; 80 if(infos[1] == "nil") 81 overload.returnType = func.owner; 82 else 83 overload.returnType = infos[1]; 84 long constInd = infos.countUntil("const"); 85 int infoIndex = 2; 86 if(constInd != -1) 87 { 88 overload.returnType~= " "~infos[constInd+1]; 89 infoIndex++; 90 } 91 overload.cimguiFunc = infos[infoIndex]; 92 93 // long argsStart = line.countUntil("("); //Not used anymore 94 getParameters(func, overload); 95 // overload.argsTypes = line[cast(uint)argsStart..line.length]; 96 func.overloads~= overload; 97 } 98 } 99 else 100 { 101 if(func.exists) 102 ret~= func; 103 func = Function(); 104 string[] infos = line.split("_"); //Gets the function name 105 if(isOnIgnoreList(line)) 106 { 107 func.exists = false; 108 continue; 109 } 110 int nameIndex = 0; 111 if(infos.length != 1) 112 { 113 func.owner = infos[0]; 114 nameIndex = 1; 115 long separatorIndex = infos[nameIndex].countUntil("\t"); 116 if(separatorIndex == -1) 117 separatorIndex = infos[nameIndex].countUntil(" "); 118 if(separatorIndex == -1) 119 return null; 120 func.name = infos[nameIndex][0..cast(uint)separatorIndex]; 121 } 122 else 123 { 124 infos = line.split(); 125 func.owner = ""; 126 func.name = infos[0]; 127 } 128 129 130 func.exists = true; 131 } 132 } 133 return ret; 134 } 135 136 string generateAliasOverload() 137 { 138 return q{ 139 static template overload(Func...) 140 { 141 import std.traits; 142 static foreach(f; Funcs) 143 auto overload(Parameters!f params){ 144 return f(params);} 145 }}; 146 } 147 148 static void getParameters(ref Function func, ref OverloadedFunction overload) 149 { 150 JSONValue jsonFunc = defs[func.fname].array; 151 foreach (JSONValue ovFunc; jsonFunc.array) 152 { 153 if(ovFunc["ov_cimguiname"].str == overload.cimguiFunc) 154 { 155 156 overload.argsTypes = ovFunc["argsoriginal"].str; 157 if(hasVarArgs(overload.argsTypes)) 158 { 159 func.willForward = true; 160 } 161 overload.argsParams = "("; 162 JSONValue argParams = ovFunc["argsT"]; 163 size_t len = argParams.array.length; 164 foreach(i, params; argParams.array) 165 { 166 overload.argsParams~= params["name"].str; 167 if(i+1 != len) 168 overload.argsParams~=","; 169 } 170 overload.argsParams~= ")"; 171 break; 172 } 173 } 174 } 175 176 static string generateOverloads(Function[] funcs) 177 { 178 string fileContent = ""; 179 string line = ""; 180 import std.format:format; 181 182 string funcName; 183 foreach(func; funcs) 184 { 185 funcName = func.name; 186 if(func.willForward) 187 { 188 if(!willDefineOverloadTemplate) 189 willDefineOverloadTemplate = true; 190 line = "alias "~funcName ~"= overload!("; 191 string comment = "/**\n"; 192 foreach(i, ov ; func.overloads) 193 { 194 comment~= "*\t"~ov.returnType~" "~funcName~ov.argsTypes~"\n"; 195 line~= ov.cimguiFunc; 196 if(i != func.overloads.length - 1) 197 line~=","; 198 //Write a comment on the alias for appearing 199 } 200 comment~="*/\n"; 201 fileContent~= comment~line~");\n"; 202 } 203 else foreach(overload; func.overloads) 204 { 205 line = overload.returnType~" "~funcName~overload.argsTypes~"{"~overload.cimguiFunc; 206 line~= overload.argsParams~";}"; 207 fileContent~= line~"\n"; 208 } 209 } 210 return fileContent; 211 } 212 213 214 static JSONValue defs = null; 215 //Will only receive the path to overloads.txt 216 217 string getOverloadsPath(string cimguiPath) 218 { 219 return cimguiPath~"/generator/output/overloads.txt"; 220 } 221 string getDefinitionsPath(string cimguiPath) 222 { 223 return cimguiPath~"/generator/output/definitions.json"; 224 } 225 226 227 class CimGuiOverloadPlugin : Plugin 228 { 229 string storedStr; 230 override string target(){return "cimgui-overloads";} 231 override string convertToD_Pipe() 232 { 233 return storedStr; 234 } 235 string outputPath; 236 override int main(string[] args) 237 { 238 239 if(args.length < 2) 240 return returnError("Argument Expected:\nNo path for cimgui provided!"); 241 else if(args.length == 3) 242 outputPath = args[2]; 243 string cimguiPath = args[1]; 244 if(!exists(cimguiPath)) 245 return returnError("Cimgui directory '"~cimguiPath~"' not found"); 246 string overloads = getOverloadsPath(cimguiPath); 247 string defsPath = getDefinitionsPath(cimguiPath); 248 249 if(!exists(overloads)) 250 return returnError("Overloads path '"~overloads~"' does not exists"); 251 if(!exists(defsPath)) 252 return returnError("Definitions path '"~defsPath~"' does not exists"); 253 254 defs = parseJSON(readText(defsPath)); 255 256 File f = File(overloads); 257 Function[] funcs = getFunctions(f); 258 storedStr = generateOverloads(funcs); 259 260 return Plugin.SUCCESS; 261 } 262 override int onReturnControl(string processedStr) 263 { 264 import std.file : write; 265 string s = "module bindbc.cimgui.overloads;\n\n"; 266 s~= "import bindbc.cimgui.funcs;\n"; 267 if(willDefineOverloadTemplate) 268 s~= generateAliasOverload(); 269 s~="\n"; 270 271 if(outputPath) 272 { 273 if(outputPath[$-1] == "/") 274 outputPath = outputPath[0..$-1]; 275 write(outputPath~"/overloads.d", s~processedStr); 276 } 277 else 278 write("overloads.d", s~processedStr); 279 return Plugin.SUCCESS; 280 } 281 override string getHelpInformation() 282 { 283 return r"This plugin was made to be used in conjunction with BindBC-Generator, located on 284 https://github.com/MrcSnm/bindbc-generator 285 286 1: Argument must be 'cimgui' path, it will look for definitions.json and overloads.txt 287 2(Optional): Output path"; 288 } 289 290 } 291 292 extern(C) export Plugin exportOverloadgen() 293 { 294 return new CimGuiOverloadPlugin(); 295 }