1 module language.d; 2 3 import godotutil..string; 4 import api.util; 5 import api.classes, api.methods; 6 7 import language; 8 9 import std.algorithm.iteration; 10 import std.range; 11 import std.path; 12 import std.conv : text; 13 import std..string; 14 15 Language getDLanguage() 16 { 17 Language ret; 18 ret.classOutputFiles = [ 19 Language.ClassOutputFile(&generateClass), 20 Language.ClassOutputFile(&generateGlobalConstants), 21 Language.ClassOutputFile(&generateGlobalEnums), 22 Language.ClassOutputFile(&generatePackage) 23 ]; 24 return ret; 25 } 26 27 28 29 30 31 private: 32 33 static immutable string copyrightNotice = 34 `Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. 35 Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) 36 Copyright (c) 2017-2018 Godot-D contributors `; 37 38 string[2] generatePackage(GodotClass c) 39 { 40 if(c.name.godot == "GlobalConstants") return [null, null]; 41 42 if(c.descendant_ptrs.length == 0) return [null, null]; 43 44 string filename = buildPath("godot", c.name.moduleName, "all.d"); 45 string ret; 46 47 ret ~= "module godot."; 48 ret ~= c.name.moduleName; 49 ret ~= ".all;\n\n"; 50 51 ret ~= "public import\n\tgodot."~c.name.moduleName; 52 53 const(GodotClass)[] recursiveDescendants; 54 void addDescendant(GodotClass d) 55 { 56 import std.algorithm.searching; 57 if(!recursiveDescendants[].canFind(d)) recursiveDescendants ~= d; 58 foreach(rd; d.descendant_ptrs[]) addDescendant(rd); 59 } 60 foreach(d; c.descendant_ptrs[]) addDescendant(d); 61 62 foreach(di, d; recursiveDescendants[]) 63 { 64 ret ~= ",\n\tgodot."~d.name.moduleName; 65 } 66 ret ~= ";\n"; 67 68 string[2] arr = [filename, ret]; 69 return arr; 70 } 71 72 73 string[2] generateClass(GodotClass c) 74 { 75 if(c.name.godot == "GlobalConstants") return [null, null]; 76 77 string folder = "godot"; 78 string filename = (c.descendant_ptrs.length == 0) ? 79 buildPath(folder, c.name.moduleName~".d") : 80 buildPath(folder, c.name.moduleName, "package.d"); 81 string ret; 82 83 ret ~= "/**\n"~c.ddocBrief~"\n\n"; 84 ret ~= "Copyright:\n"~copyrightNotice~"\n\n"; 85 ret ~= "License: $(LINK2 https://opensource.org/licenses/MIT, MIT License)\n\n"; 86 ret ~= "\n*/\n"; 87 88 // module names should be all lowercase in D 89 // https://dlang.org/dstyle.html 90 ret ~= "module godot."; 91 ret ~= c.name.moduleName; 92 ret ~= ";\n"; 93 ret ~= "import std.meta : AliasSeq, staticIndexOf;\n"; 94 ret ~= "import std.traits : Unqual;\n"; 95 ret ~= "import godot.d.traits;\nimport godot.core;\nimport godot.c;\n"; 96 ret ~= "import godot.d.bind;\n"; 97 ret ~= "import godot.d.reference;\n"; 98 ret ~= "import godot.globalenums;\n"; 99 if(c.name.godot != "Object") ret ~= "import godot.object;\n"; 100 101 if(c.instanciable) 102 { 103 ret ~= "import godot.classdb;\n"; 104 } 105 106 ret ~= c.source; 107 108 string[2] arr = [filename, ret]; 109 return arr; 110 } 111 112 string[2] generateGlobalConstants(GodotClass c) 113 { 114 import std.conv : text; 115 import std..string; 116 import std.meta; 117 import std.algorithm.iteration, std.algorithm.searching, std.algorithm.sorting; 118 import std.range : array; 119 120 if(c.name.godot != "GlobalConstants") return [null, null]; 121 122 string filename = buildPath("godot", "globalconstants.d"); 123 string ret; 124 125 ret ~= "/// \n"; 126 ret ~= "module godot.globalconstants;\n"; 127 ret ~= "public import godot.globalenums;\n"; 128 129 foreach(const string name, const int value; c.constants) 130 { 131 ret ~= "enum int "~name.snakeToCamel.escapeD~" = "~text(value)~";\n"; 132 } 133 134 string[2] arr = [filename, ret]; 135 return arr; 136 } 137 138 string[2] generateGlobalEnums(GodotClass c) 139 { 140 import std.conv : text; 141 import std..string; 142 import std.meta; 143 import std.algorithm.iteration, std.algorithm.searching, std.algorithm.sorting; 144 import std.range : array; 145 146 if(c.name.godot != "GlobalConstants") return [null, null]; 147 148 string filename = buildPath("godot", "globalenums.d"); 149 string ret; 150 151 ret ~= "/// \n"; 152 ret ~= "module godot.globalenums;\n"; 153 154 /// Try to put at least some of these in grouped enums 155 static struct Group 156 { 157 string name; /// The name of the new enum 158 string prefix; /// The prefix to strip from original name 159 } 160 161 alias groups = AliasSeq!( 162 Group("Key", "KEY_"), 163 Group("MouseButton", "BUTTON_"), 164 Group("PropertyHint", "PROPERTY_HINT_"), 165 Group("PropertyUsage", "PROPERTY_USAGE_"), 166 Group("Type", "TYPE_") 167 ); 168 169 foreach(g; groups) 170 { 171 ret ~= "enum "~g.name~" : int\n{\n"; 172 173 foreach(const string name; c.constants.keys[].filter!(k => k.startsWith(g.prefix)) 174 .array.sort!((a,b) => c.constants[a] < c.constants[b])) 175 { 176 ret ~= "\t" ~ name[g.prefix.length..$].snakeToCamel.escapeD 177 ~ " = " ~ text(c.constants[name]) ~ ",\n"; 178 } 179 180 ret ~= "}\n"; 181 } 182 183 // Godot itself never refers to these, but some modules like Goost do. 184 // Allow bindings for them to compile by keeping the original names. 185 string[2][] aliases = [["KeyList", "Key"], ["PropertyUsageFlags", "PropertyUsage"], ["ButtonList", "MouseButton"]]; 186 foreach(a; aliases) 187 { 188 ret ~= "alias " ~ a[0] ~ " = " ~ a[1] ~ ";\n"; 189 } 190 191 string[2] arr = [filename, ret]; 192 return arr; 193 } 194 195