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