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