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