1 module IDL.idl_parse;
2 
3 import std.array;
4 import std.range.primitives : popFrontN;
5 import std.array : appender;
6 import std.regex;
7 import std.stdio;
8 import std.conv;
9 import std.file;
10 import std.format;
11 import std.process;
12 
13 import IDL.IdlSymbol;
14 import IDL.IdlParseStruct;
15 import IDL.IdlParseInterface;
16 import IDL.IdlBaseInterface;
17 import IDL.IdlFlatbufferCreateCode;
18 import IDL.IdlUnit;
19 
20 import core.thread;
21 
22 class idl_parse
23 {
24 	this()
25 	{
26 		//idlDlangVariable["void"] = "void";
27 		idlDlangVariable["bool"] = "bool";
28 		idlDlangVariable["byte"] = "byte";
29 		idlDlangVariable["ubyte"] = "ubyte";
30 		idlDlangVariable["short"] = "short";
31 		idlDlangVariable["ushort"] = "ushort";
32 		idlDlangVariable["int"] = "int";
33 		idlDlangVariable["uint"] = "uint";
34 		idlDlangVariable["long"] = "long";
35 		idlDlangVariable["ulong"] = "ulong";
36 		idlDlangVariable["float"] = "float";
37 		idlDlangVariable["double"] = "double";
38 		idlDlangVariable["char"] = "char";
39 		idlDlangVariable["string"] = "string";
40 	}
41 
42 	void setParseFile(string path)
43 	{
44 		inFilePath = path;
45 	}
46 
47 	void setOutputFile(string path)
48 	{
49 		outFilePath = path;
50 	}
51 
52 	void setFileName(string name)
53 	{
54 		fileName = name;
55 	}
56 
57 	void startParse()
58 	{
59 		auto file = File(inFilePath);
60 	
61 		string text;
62 
63 		while(!file.eof)
64 		{
65 			text ~= file.readln();
66 		}
67 
68 		this.parse(text);
69 	}
70 
71 	bool parse(string data)
72 	{
73 		data = replaceAll(data, regex(`\/\/[^\n]*`), "");
74 		data = replaceAll(data, regex("\n|\t"), "");
75 		data = replaceAll(data, regex(`\s{2,}`), "");
76 
77 		auto clesses = split(data, regex(`[@\}]`));
78 
79 		if(clesses.length == 0)
80 		{
81 			throw new Exception("parse classes is failed, no class struct!!", data);
82 		}
83 
84 		foreach(c; clesses)
85 		{
86 				auto symbolFlag = split(c, "{");
87 				
88 				if(symbolFlag.length == 2)
89 				{
90 					
91 					auto symbolAttr = split(symbolFlag[0], ":");
92 					
93 					if(symbolAttr.length != 2)
94 					{
95 						throw new Exception("parse symbol  attr is failed,  symbol missing :, " ~ symbolFlag[0]);
96 					}
97 
98 					IdlBaseInterface idlInterface;
99 
100 					switch(symbolAttr[0])
101 					{
102 						case SYMBOL_STRUCT:
103 							idlInterface  = new IdlParseStruct;
104 							break;
105 
106 						case SYMBOL_INTERFACE:
107 							idlInterface = new IdlParseInterface;
108 							break;	
109 
110 						default:
111 							throw new Exception("parse symbol attr is error,  symbol: " ~ symbolAttr[0]);
112 					}
113 					
114 				if(idlInterface.parse(fileName, symbolAttr[1], symbolFlag[1]))
115 					{
116 						switch(symbolAttr[0])
117 						{
118 							case SYMBOL_STRUCT:
119 								idlStructList[idlInterface.getName] = cast(IdlParseStruct)idlInterface;
120 								break;
121 
122 							case SYMBOL_INTERFACE:
123 								idlInerfaceList[idlInterface.getName] = idlInterface;
124 								break;
125 
126 							default:
127 								throw new Exception("parse symbol attr is error,  symbol: " ~ symbolAttr[0]);
128 						}
129 					}
130 			}
131 		}
132 
133 		this.create_code();
134 		return true;
135 	}
136 
137 
138 	void create_code()
139 	{
140 		string serverCodeInterface, serverCodeService;
141 		string clientCodeInterface, clientCodeService;
142 		string structCode;
143 		string flatbufferIdlCode;
144 
145 		auto serverInterfaceStrings = appender!string();
146 		formattedWrite(serverInterfaceStrings, "module kissrpc.generated.%sInterface;\n\n", fileName);
147 		formattedWrite(serverInterfaceStrings, "import kissrpc.generated.%sMessage;\n", fileName);
148 		formattedWrite(serverInterfaceStrings, "import kissrpc.generated.%sService;\n\n", fileName);
149 
150 
151 
152 		formattedWrite(serverInterfaceStrings, "import kissrpc.RpcServer;\n");
153 		formattedWrite(serverInterfaceStrings, "import kissrpc.RpcServerImpl;\n");
154 		formattedWrite(serverInterfaceStrings, "import kissrpc.RpcResponse;\n");
155 		formattedWrite(serverInterfaceStrings, "import kissrpc.RpcRequest;\n");
156 		formattedWrite(serverInterfaceStrings, "import flatbuffers;\n");
157 
158 		auto server_service_strings = appender!string();
159 		formattedWrite(server_service_strings, "module kissrpc.generated.%sService;\n\n", fileName);
160 		formattedWrite(server_service_strings, "import kissrpc.generated.%sInterface;\n", fileName);
161 		formattedWrite(server_service_strings, "import kissrpc.generated.%sMessage;\n\n", fileName);
162 		formattedWrite(server_service_strings, "import kissrpc.RpcServer;\n");
163 		formattedWrite(server_service_strings, "import kissrpc.Unit;\n\n");
164 
165 		auto client_interface_strings = appender!string();
166 		formattedWrite(client_interface_strings, "module kissrpc.generated.%sInterface;\n\n", fileName);
167 		formattedWrite(client_interface_strings, "import kissrpc.generated.%sMessage;\n", fileName);
168 		formattedWrite(client_interface_strings, "import kissrpc.generated.%sService;\n\n", fileName);
169 
170 		formattedWrite(client_interface_strings, "import kissrpc.RpcRequest;\n");
171 		formattedWrite(client_interface_strings, "import kissrpc.RpcClientImpl;\n");
172 		formattedWrite(client_interface_strings, "import kissrpc.RpcClient;\n");
173 		formattedWrite(client_interface_strings, "import kissrpc.RpcResponse;\n");
174 		formattedWrite(client_interface_strings, "import kissrpc.Unit;\n");
175 		formattedWrite(client_interface_strings, "import flatbuffers;\n");
176 
177 
178 		auto client_service_strings = appender!string();
179 		formattedWrite(client_service_strings, "module kissrpc.generated.%sService;\n\n\n", fileName);
180 		formattedWrite(client_service_strings, "import kissrpc.generated.%sInterface;\n", fileName);
181 		formattedWrite(client_service_strings, "import kissrpc.generated.%sMessage;\n\n", fileName);
182 		formattedWrite(client_service_strings, "import kissrpc.RpcClient;\n");
183 		formattedWrite(client_service_strings, "import kissrpc.Unit;\n\n");
184 
185 
186 
187 		auto struct_strings = appender!string();
188 		formattedWrite(struct_strings, "module kissrpc.generated.%sMessage;\n", fileName);
189 		formattedWrite(struct_strings, "import std.typetuple;\n\n\n");
190 	
191 
192 
193 		foreach(k, v; idlInerfaceList)
194 		{
195 			serverCodeInterface ~= v.createServerCodeForInterface(CODE_LANGUAGE.CL_DLANG);
196 			serverCodeService ~= v.createServerCodeForService(CODE_LANGUAGE.CL_DLANG);
197 
198 			clientCodeInterface ~= v.createClientCodeForInterface(CODE_LANGUAGE.CL_DLANG);
199 			clientCodeService ~= v.createClientCodeForService(CODE_LANGUAGE.CL_DLANG);
200 		}
201 
202 		foreach(k, v; idlStructList)
203 		{
204 			structCode ~= v.createCodeForLanguage(CODE_LANGUAGE.CL_DLANG);
205 		}
206 
207 		foreach(k,v; idlStructList)
208 		{
209 			flatbufferIdlCode ~= IdlFlatbufferCode.createFlatbufferCode(v);
210 		}
211 
212 
213 		auto flatbuffer_strings = appender!string();
214 
215 
216 		auto modulePath = split(fileName, ".");
217 
218 		// if(modulePath.length > 1)
219 		// {
220 		// 	for(int i = 0; i < modulePath.length-1; ++i)
221 		// 	{
222 		// 		outFilePath ~= ("/" ~ modulePath[i]);
223 		// 		if(!exists(outFilePath)) {
224 		// 			rmdir(outFilePath);
225 		// 		}
226 		// 		mkdir(outFilePath);
227 		// 		moduleFilePath ~= (modulePath[i] ~ ".");
228 		// 	}
229 			
230 		// 	fileName = modulePath[modulePath.length-1];
231 		
232 		// 	formattedWrite(flatbuffer_strings, "namespace kissrpc.generated.%smessage;\n\n", moduleFilePath);
233 		// 	formattedWrite(serverInterfaceStrings, "import kissrpc.generated.%smessage.%s;\n\n", moduleFilePath, fileName);
234 		// 	formattedWrite(client_interface_strings, "import kissrpc.generated.%smessage.%s;\n\n", moduleFilePath, fileName);
235 		// }else
236 		// {
237 		// 	formattedWrite(flatbuffer_strings, "namespace kissrpc.generated.message.hakar;\n\n");
238 		// 	formattedWrite(serverInterfaceStrings, "import kissrpc.generated.message.%s;\n\n",fileName);
239 		// 	formattedWrite(client_interface_strings, "import kissrpc.generated.message.%s;\n\n", fileName);
240 		// }
241 
242 
243 
244 		if (!exists(outFilePath ~ "/kissrpc/")) {
245 			mkdir(outFilePath ~ "/kissrpc/");
246 		}
247 		outFilePath ~= "/kissrpc";
248 
249 		if (!exists(outFilePath ~ "/generated")) {
250 			mkdir(outFilePath ~ "/generated");
251 		}
252 		outFilePath ~= "/generated";
253 
254 
255 		formattedWrite(flatbuffer_strings, "namespace kissrpc.generated.message;\n\n");
256 		formattedWrite(serverInterfaceStrings, "import kissrpc.generated.message.%s;\n\n",fileName);
257 		formattedWrite(client_interface_strings, "import kissrpc.generated.message.%s;\n\n", fileName);
258 
259 
260 		
261 		//generated server
262 		if(!exists(outFilePath ~ "/server/"))
263 		{
264 			mkdir(outFilePath ~ "/server/");
265 		}
266 		auto file = File(outFilePath ~ "/server/" ~ fileName ~ "Interface.d", "w+");
267 		file.write(serverInterfaceStrings.data ~ serverCodeInterface);
268 		file.close();
269 
270 
271 		file = File(outFilePath ~ "/server/" ~ fileName ~ "Service.d", "w+");
272 		file.write(server_service_strings.data ~ serverCodeService);
273 		file.close();
274 
275 
276 		//generated client
277 		if(!exists(outFilePath ~ "/client/"))
278 		{
279 			mkdir(outFilePath ~ "/client/");
280 		}
281 
282 		file = File(outFilePath ~ "/client/" ~ fileName ~ "Interface.d", "w+");
283 		file.write(client_interface_strings.data ~ clientCodeInterface);
284 		file.close();
285 
286 		file = File(outFilePath ~ "/client/" ~ fileName ~ "Service.d", "w+");
287 		file.write(client_service_strings.data ~ clientCodeService);
288 		file.close();
289 		
290 
291 
292 		//generated message
293 		if(!exists(outFilePath ~ "/message/"))
294 		{
295 			mkdir(outFilePath ~ "/message/");
296 		}
297 
298 		file = File(outFilePath ~ "/message/" ~ fileName ~ "Message.d", "w+");
299 		file.write(struct_strings.data ~ structCode);
300 		file.close();
301 
302 
303 		file = File(outFilePath ~ "/message/" ~ fileName ~ ".fbs", "w+");
304 		file.write(flatbuffer_strings.data ~ flatbufferIdlCode);
305 
306 		spawnProcess(["flatc", "-d", "-b", outFilePath ~ "/message/" ~ fileName ~ ".fbs", "--gen-onefile"],
307 			std.stdio.stdin, std.stdio.stdout, std.stdio.stderr, null, Config.none, outFilePath ~ "/message/");
308 		
309 		
310 		
311 		new Thread({
312 			Thread.sleep(2000.msecs); 
313 			auto b = std.file.read(outFilePath ~ "/message/" ~ fileName ~ ".d");
314 			
315 			string bb = cast(string)b;
316 			file = File(outFilePath ~ "/message/" ~ fileName ~ ".d", "w+");
317 			
318 			auto apstring = appender!string();
319 			formattedWrite(apstring, "module kissrpc.generated.message.%s;\n\n%s", fileName,bb);
320 			file.write(apstring.data);
321 			file.close();
322 
323 		}).start();
324 
325 
326 
327 	}
328 
329 private:
330 	IdlBaseInterface[string] idlInerfaceList;
331 
332 	string inFilePath = ".";
333 	string outFilePath = ".";
334 	string fileName;
335 	string moduleFilePath;
336 }
337