CSModuleWriter.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. //
  2. // Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include <Atomic/IO/File.h>
  23. #include <Atomic/IO/FileSystem.h>
  24. #include "../JSBind.h"
  25. #include "../JSBPackage.h"
  26. #include "../JSBModule.h"
  27. #include "../JSBEnum.h"
  28. #include "../JSBClass.h"
  29. #include "../JSBFunction.h"
  30. #include "../JSBEvent.h"
  31. #include "CSTypeHelper.h"
  32. #include "CSClassWriter.h"
  33. #include "CSModuleWriter.h"
  34. namespace ToolCore
  35. {
  36. CSModuleWriter::CSModuleWriter(JSBModule *module) : JSBModuleWriter(module)
  37. {
  38. }
  39. void CSModuleWriter::WriteIncludes(String& source)
  40. {
  41. Vector<String>& includes = module_->includes_;
  42. for (unsigned i = 0; i < includes.Size(); i++)
  43. {
  44. if (includes[i].StartsWith("<"))
  45. source.AppendWithFormat("#include %s\n", includes[i].CString());
  46. else
  47. source.AppendWithFormat("#include \"%s\"\n", includes[i].CString());
  48. }
  49. Vector<JSBHeader*> allheaders;
  50. HashMap<StringHash, SharedPtr<JSBEnum> >::Iterator eitr = module_->enums_.Begin();
  51. while (eitr != module_->enums_.End())
  52. {
  53. allheaders.Push(eitr->second_->GetHeader());
  54. eitr++;
  55. }
  56. HashMap<StringHash, SharedPtr<JSBClass> >::Iterator citr = module_->classes_.Begin();
  57. while (citr != module_->classes_.End())
  58. {
  59. allheaders.Push(citr->second_->GetHeader());
  60. citr++;
  61. }
  62. Vector<JSBHeader*> included;
  63. for (unsigned i = 0; i < allheaders.Size(); i++)
  64. {
  65. JSBHeader* header = allheaders.At(i);
  66. if (included.Contains(header))
  67. continue;
  68. String headerPath = GetPath(header->GetFilePath());
  69. String headerfile = GetFileNameAndExtension(header->GetFilePath());
  70. JSBind* jsbind = header->GetSubsystem<JSBind>();
  71. headerPath.Replace(jsbind->GetSourceRootFolder() + "Source/", "");
  72. source.AppendWithFormat("#include <%s%s>\n", headerPath.CString(), headerfile.CString());
  73. included.Push(header);
  74. }
  75. source += "\n#include <Atomic/Script/ScriptVector.h>\n";
  76. source += ToString("\n#include \"CSPackage%s.h\"\n", module_->GetPackage()->GetName().CString());
  77. }
  78. void CSModuleWriter::GenerateNativeSource()
  79. {
  80. String source = "// This file was autogenerated by JSBind, changes will be lost\n";
  81. String moduleGuard = module_->GetModuleDefineGuard();
  82. if (moduleGuard.Length())
  83. {
  84. source += ToString("\n%s\n", moduleGuard.CString());
  85. }
  86. source += "#ifdef ATOMIC_PLATFORM_WINDOWS\n";
  87. source += "#pragma warning(disable: 4244) // possible loss of data\n";
  88. source += "#define ATOMIC_EXPORT_API __declspec(dllexport)\n";
  89. source += "#else\n";
  90. source += "#define ATOMIC_EXPORT_API\n";
  91. source += "#endif\n";
  92. if (module_->Requires("3D"))
  93. {
  94. source += "#ifdef ATOMIC_3D\n";
  95. }
  96. WriteIncludes(source);
  97. source += "\n#include <AtomicNET/NETNative/NETCore.h>\n";
  98. String ns = module_->GetPackage()->GetNamespace();
  99. source += "\n\nusing namespace " + ns + ";\n\n";
  100. source += "\n\nextern \"C\" \n{\n \n";
  101. source += "// Begin Class Declarations\n";
  102. source += "// End Class Declarations\n\n";
  103. source += "// Begin Classes\n";
  104. Vector<SharedPtr<JSBClass>> classes = module_->classes_.Values();
  105. for (unsigned i = 0; i < classes.Size(); i++)
  106. {
  107. String classGuard = module_->GetClassDefineGuard(classes[i]->GetNativeName());
  108. if (classGuard.Length())
  109. {
  110. source += ToString("\n%s\n\n", classGuard.CString());
  111. }
  112. CSClassWriter clsWriter(classes[i]);
  113. clsWriter.GenerateNativeSource(source);
  114. if (classGuard.Length())
  115. {
  116. source += "#endif\n\n";
  117. }
  118. }
  119. source += "// End Classes\n\n";
  120. // end Atomic namespace
  121. source += "\n}\n";
  122. if (module_->Requires("3D"))
  123. {
  124. source += "#endif //ATOMIC_3D\n";
  125. }
  126. if (moduleGuard.Length())
  127. {
  128. source += "\n#endif\n";
  129. }
  130. JSBind* jsbind = module_->GetSubsystem<JSBind>();
  131. String filepath = jsbind->GetDestNativeFolder() + "/CSModule" + module_->name_ + ".cpp";
  132. File file(module_->GetContext());
  133. file.Open(filepath, FILE_WRITE);
  134. file.Write(source.CString(), source.Length());
  135. file.Close();
  136. }
  137. String CSModuleWriter::GetManagedPrimitiveType(JSBPrimitiveType* ptype)
  138. {
  139. if (ptype->kind_ == JSBPrimitiveType::Bool)
  140. return "bool";
  141. if (ptype->kind_ == JSBPrimitiveType::Int && ptype->isUnsigned_)
  142. return "uint";
  143. else if (ptype->kind_ == JSBPrimitiveType::Int)
  144. return "int";
  145. if (ptype->kind_ == JSBPrimitiveType::Float)
  146. return "float";
  147. return "int";
  148. }
  149. void CSModuleWriter::GenerateManagedClasses(String& source)
  150. {
  151. Vector<SharedPtr<JSBClass>> classes = module_->classes_.Values();
  152. for (unsigned i = 0; i < classes.Size(); i++)
  153. {
  154. JSBClass* klass = classes.At(i);
  155. if (klass->IsNumberArray())
  156. continue;
  157. CSClassWriter clsWriter(klass);
  158. clsWriter.GenerateManagedSource(source);
  159. }
  160. }
  161. void CSModuleWriter::GenerateManagedEnumsAndConstants(String& source)
  162. {
  163. Vector<SharedPtr<JSBEnum>> enums = module_->enums_.Values();
  164. Indent();
  165. for (unsigned i = 0; i < enums.Size(); i++)
  166. {
  167. JSBEnum* jenum = enums[i];
  168. source += "\n";
  169. String line = "public enum " + jenum->GetName() + "\n";
  170. source += IndentLine(line);
  171. source += IndentLine("{\n");
  172. HashMap<String, String>& values = jenum->GetValues();
  173. HashMap<String, String>::ConstIterator itr = values.Begin();
  174. Indent();
  175. while (itr != values.End())
  176. {
  177. String name = (*itr).first_;
  178. String value = (*itr).second_;
  179. // BodyType2D enum order is assigned in RigidBody2D.h in incorrect order
  180. if (jenum->GetName() == "BodyType2D")
  181. {
  182. if (name == "BT_STATIC")
  183. value = "0";
  184. else if (name == "BT_KINEMATIC")
  185. value = "1";
  186. else if (name == "BT_DYNAMIC")
  187. value = "2";
  188. }
  189. if (value.Length())
  190. {
  191. line = name + " = " + value;
  192. }
  193. else
  194. {
  195. line = name;
  196. }
  197. itr++;
  198. if (itr != values.End())
  199. line += ",";
  200. line += "\n";
  201. source += IndentLine(line);
  202. }
  203. Dedent();
  204. source += IndentLine("}\n");
  205. }
  206. // constants
  207. HashMap<String, JSBModule::Constant>& constants = module_->GetConstants();
  208. if (constants.Size())
  209. {
  210. source += "\n";
  211. String line = "public static partial class Constants\n";
  212. source += IndentLine(line);
  213. source += IndentLine("{\n");
  214. const Vector<String>& constantsName = constants.Keys();
  215. Indent();
  216. for (unsigned i = 0; i < constantsName.Size(); i++)
  217. {
  218. const String& cname = constantsName.At(i);
  219. JSBModule::Constant& constant = constants[cname];
  220. String managedType = GetManagedPrimitiveType(constant.type);
  221. String value = constant.value;
  222. if (!value.Length())
  223. continue;
  224. //static const unsigned M_MIN_UNSIGNED = 0x00000000;
  225. // /static const unsigned M_MAX_UNSIGNED = 0xffffffff;
  226. if (cname == "M_MIN_INT")
  227. value = "int.MinValue";
  228. if (cname == "M_INFINITY")
  229. value = "float.MaxValue";
  230. if (value == "M_MAX_UNSIGNED")
  231. value = "0xffffffff";
  232. // Input stuff
  233. if (module_->GetName() == "Input")
  234. {
  235. if (cname.StartsWith("KEY_"))
  236. {
  237. if (value.Length() == 1 && (IsAlpha(value[0]) || IsDigit(value[0])))
  238. value = "'" + value + "'";
  239. }
  240. // https://raw.githubusercontent.com/flibitijibibo/SDL2-CS/master/src/SDL2.cs
  241. if (value.StartsWith("SDL_BUTTON_") || value.StartsWith("SDL_HAT_"))
  242. {
  243. value = "(int) SDL." + value;
  244. }
  245. else if (value.StartsWith("SDLK_"))
  246. {
  247. value = "(int) SDL.SDL_Keycode." + value;
  248. }
  249. else if (value.StartsWith("SDL_SCANCODE_"))
  250. {
  251. value = "(int) SDL.SDL_Scancode." + value;
  252. }
  253. else if (value.StartsWith("SDL_CONTROLLER_BUTTON_"))
  254. {
  255. value = "(int) SDL.SDL_GameControllerButton." + value;
  256. }
  257. else if (value.StartsWith("SDL_CONTROLLER_AXIS_"))
  258. {
  259. value = "(int) SDL.SDL_GameControllerAxis." + value;
  260. }
  261. }
  262. String line = "public const " + managedType + " " + cname + " = " + value;
  263. if (managedType == "float" && !line.EndsWith("f") && IsDigit(line[line.Length()-1]))
  264. line += "f";
  265. line += ";\n";
  266. source += IndentLine(line);
  267. }
  268. Dedent();
  269. source += "\n";
  270. line = "}\n";
  271. source += IndentLine(line);
  272. }
  273. source += "\n";
  274. Dedent();
  275. }
  276. void CSModuleWriter::GenerateManagedNativeEvents(String& sourceOut)
  277. {
  278. Indent();
  279. String source;
  280. const Vector<SharedPtr<JSBEvent>>& events = module_->GetEvents();
  281. for (unsigned i = 0; i < events.Size(); i++)
  282. {
  283. JSBEvent* event = events[i];
  284. const String& eventID = event->GetEventID();
  285. String line = ToString("public partial class %s : NativeEventData\n", event->GetScriptEventName().CString());
  286. source += IndentLine(line);
  287. source += IndentLine("{\n\n");
  288. Indent();
  289. // parameters
  290. const Vector<JSBEvent::EventParam>& params = event->GetParameters();
  291. for (unsigned j = 0; j < params.Size(); j++)
  292. {
  293. const JSBEvent::EventParam& p = params[j];
  294. JSBClass* cls = JSBPackage::GetClassAllPackages(p.typeInfo_);
  295. String typeName = p.typeInfo_;
  296. String enumTypeName = p.enumTypeName_;
  297. if (!cls)
  298. typeName = typeName.ToLower();
  299. else
  300. typeName = cls->GetName();
  301. if (typeName == "int" || typeName == "float" ||
  302. typeName == "bool" || typeName == "string" || typeName == "enum" || cls)
  303. {
  304. bool isEnum = false;
  305. if (typeName == "enum")
  306. {
  307. isEnum = true;
  308. if (enumTypeName.Length())
  309. typeName = enumTypeName;
  310. else
  311. typeName = "int";
  312. }
  313. line = "public " + typeName + " " + p.paramName_ + "\n";
  314. source += IndentLine(line);
  315. source += IndentLine("{\n");
  316. Indent();
  317. source += IndentLine("get\n");
  318. source += IndentLine("{\n");
  319. Indent();
  320. line = "return ";
  321. if (typeName == "int")
  322. line += "scriptMap.GetInt";
  323. else if (isEnum)
  324. {
  325. line += ToString("(%s) scriptMap.GetInt", typeName.CString());
  326. }
  327. else if (typeName == "float")
  328. line += "scriptMap.GetFloat";
  329. else if (typeName == "bool")
  330. line += "scriptMap.GetBool";
  331. else if (typeName == "string")
  332. line += "scriptMap.GetString";
  333. else if (cls)
  334. {
  335. if (typeName == "Vector3")
  336. {
  337. line += "scriptMap.Get" + typeName;
  338. }
  339. else
  340. {
  341. line += ToString("scriptMap.GetPtr<%s>", cls->GetName().CString());
  342. }
  343. }
  344. line += ToString("(\"%s\");\n", p.paramName_.CString());
  345. source += IndentLine(line);
  346. Dedent();
  347. source += IndentLine("}\n");
  348. Dedent();
  349. source += IndentLine("}\n\n");
  350. }
  351. }
  352. Dedent();
  353. source += IndentLine("}\n\n");
  354. }
  355. sourceOut += source;
  356. Dedent();
  357. }
  358. void CSModuleWriter::GenerateManagedModuleClass(String& sourceOut)
  359. {
  360. Indent();
  361. String source;
  362. String line = ToString("public static partial class %sModule\n", module_->GetName().CString());
  363. source += IndentLine(line);
  364. source += IndentLine("{\n");
  365. Indent();
  366. source += IndentLine("public static void Initialize()\n");
  367. source += IndentLine("{\n");
  368. Indent();
  369. Vector<SharedPtr<JSBClass>> classes = module_->classes_.Values();
  370. for (unsigned i = 0; i < classes.Size(); i++)
  371. {
  372. JSBClass* klass = classes.At(i);
  373. JSBPackage* package = module_->GetPackage();
  374. if (klass->IsNumberArray() || klass->IsAbstract())
  375. continue;
  376. const char* className = klass->GetName().CString();
  377. String classGuard = module_->GetClassDefineGuard(classes[i]->GetNativeName(), "csharp");
  378. if (classGuard.Length())
  379. {
  380. source += ToString("\n%s\n", classGuard.CString());
  381. }
  382. line = ToString("new NativeType(%s.csb_%s_%s_GetClassIDStatic (), ", className, package->GetName().CString(), className);
  383. line += ToString("typeof(%s), (IntPtr x) => { return new %s (x); } );\n",className, className);
  384. source += IndentLine(line);
  385. if (classGuard.Length())
  386. {
  387. source += ToString("#endif\n", classGuard.CString());
  388. }
  389. }
  390. source += "\n";
  391. // Native Events
  392. const Vector<SharedPtr<JSBEvent>>& events = module_->GetEvents();
  393. for (unsigned i = 0; i < events.Size(); i++)
  394. {
  395. JSBEvent* event = events[i];
  396. line = ToString("NativeEvents.RegisterEventID<%s>(\"%s\");\n", event->GetScriptEventName().CString(), event->GetEventName().CString());
  397. source += IndentLine(line);
  398. }
  399. Dedent();
  400. source += IndentLine("}\n");
  401. Dedent();
  402. source += IndentLine("}\n");
  403. sourceOut += source;
  404. Dedent();
  405. }
  406. void CSModuleWriter::GenerateManagedSource()
  407. {
  408. String source = "// Autogenerated";
  409. String moduleName = module_->GetPackage()->GetNamespace();
  410. source += "\nusing System;\nusing System.Collections.Generic;\nusing System.Runtime.InteropServices;\nusing static System.Reflection.IntrospectionExtensions;\n";
  411. if (moduleName == "Atomic")
  412. moduleName = "AtomicEngine";
  413. if (moduleName != "AtomicEngine")
  414. {
  415. source += "using AtomicEngine;\n";
  416. }
  417. source += "\n\n";
  418. source += "namespace " + moduleName + "\n";
  419. source += "{\n";
  420. GenerateManagedEnumsAndConstants(source);
  421. GenerateManagedNativeEvents(source);
  422. GenerateManagedModuleClass(source);
  423. GenerateManagedClasses(source);
  424. source += "}\n";
  425. JSBind* jsbind = module_->GetSubsystem<JSBind>();
  426. String filepath = jsbind->GetDestScriptFolder() + "/CSModule" + module_->name_ + ".cs";
  427. File file(module_->GetContext());
  428. file.Open(filepath, FILE_WRITE);
  429. file.Write(source.CString(), source.Length());
  430. file.Close();
  431. }
  432. void CSModuleWriter::GenerateSource()
  433. {
  434. GenerateNativeSource();
  435. GenerateManagedSource();
  436. }
  437. }