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