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