CSModuleWriter.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  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. Vector<SharedPtr<JSBClass>> classes = module_->GetClasses();
  57. Vector<SharedPtr<JSBClass>>::Iterator citr = classes.Begin();
  58. while (citr != classes.End())
  59. {
  60. allheaders.Push((*citr)->GetHeader());
  61. citr++;
  62. }
  63. Vector<JSBHeader*> included;
  64. for (unsigned i = 0; i < allheaders.Size(); i++)
  65. {
  66. JSBHeader* header = allheaders.At(i);
  67. if (included.Contains(header))
  68. continue;
  69. String headerPath = GetPath(header->GetFilePath());
  70. String headerfile = GetFileNameAndExtension(header->GetFilePath());
  71. JSBind* jsbind = header->GetSubsystem<JSBind>();
  72. headerPath.Replace(jsbind->GetSourceRootFolder() + "Source/", "");
  73. source.AppendWithFormat("#include <%s%s>\n", headerPath.CString(), headerfile.CString());
  74. included.Push(header);
  75. }
  76. source += "\n#include <Atomic/Script/ScriptVector.h>\n";
  77. source += ToString("\n#include \"CSPackage%s.h\"\n", module_->GetPackage()->GetName().CString());
  78. }
  79. void CSModuleWriter::GenerateNativeSource()
  80. {
  81. String source = "// This file was autogenerated by JSBind, changes will be lost\n";
  82. String moduleGuard = module_->GetModuleDefineGuard();
  83. if (moduleGuard.Length())
  84. {
  85. source += ToString("\n%s\n", moduleGuard.CString());
  86. }
  87. source += "#ifdef ATOMIC_PLATFORM_WINDOWS\n";
  88. source += "#pragma warning(disable: 4244) // possible loss of data\n";
  89. source += "#define ATOMIC_EXPORT_API __declspec(dllexport)\n";
  90. source += "#else\n";
  91. source += "#define ATOMIC_EXPORT_API\n";
  92. source += "#endif\n";
  93. if (module_->Requires("3D"))
  94. {
  95. source += "#ifdef ATOMIC_3D\n";
  96. }
  97. WriteIncludes(source);
  98. // NOTE: We include Deserializer/Serializer here as they are interfaces
  99. // If additional interfaces are introduced, consider generalizing this
  100. source += "\n#include <Atomic/IO/Deserializer.h>\n";
  101. source += "#include <Atomic/IO/Serializer.h>\n";
  102. source += "#include <AtomicNET/NETNative/NETCore.h>\n";
  103. String ns = module_->GetPackage()->GetNamespace();
  104. source += "\n\nusing namespace " + ns + ";\n\n";
  105. source += "\n\nextern \"C\" \n{\n \n";
  106. source += "// Begin Class Declarations\n";
  107. source += "// End Class Declarations\n\n";
  108. source += "// Begin Classes\n";
  109. Vector<SharedPtr<JSBClass>> classes = module_->GetClasses();
  110. for (unsigned i = 0; i < classes.Size(); i++)
  111. {
  112. String classGuard = module_->GetClassDefineGuard(classes[i]->GetNativeName());
  113. if (classGuard.Length())
  114. {
  115. source += ToString("\n%s\n\n", classGuard.CString());
  116. }
  117. CSClassWriter clsWriter(classes[i]);
  118. clsWriter.GenerateNativeSource(source);
  119. if (classGuard.Length())
  120. {
  121. source += "#endif\n\n";
  122. }
  123. }
  124. source += "// End Classes\n\n";
  125. // end Atomic namespace
  126. source += "\n}\n";
  127. if (module_->Requires("3D"))
  128. {
  129. source += "#endif //ATOMIC_3D\n";
  130. }
  131. if (moduleGuard.Length())
  132. {
  133. source += "\n#endif\n";
  134. }
  135. JSBind* jsbind = module_->GetSubsystem<JSBind>();
  136. String filepath = jsbind->GetDestNativeFolder() + "/CSModule" + module_->name_ + ".cpp";
  137. File file(module_->GetContext());
  138. file.Open(filepath, FILE_WRITE);
  139. file.Write(source.CString(), source.Length());
  140. file.Close();
  141. }
  142. String CSModuleWriter::GetManagedPrimitiveType(JSBPrimitiveType* ptype)
  143. {
  144. if (ptype->kind_ == JSBPrimitiveType::Bool)
  145. return "bool";
  146. if (ptype->kind_ == JSBPrimitiveType::Int && ptype->isUnsigned_)
  147. return "uint";
  148. else if (ptype->kind_ == JSBPrimitiveType::Int)
  149. return "int";
  150. if (ptype->kind_ == JSBPrimitiveType::Float)
  151. return "float";
  152. return "int";
  153. }
  154. void CSModuleWriter::GenerateManagedClasses(String& source)
  155. {
  156. Vector<SharedPtr<JSBClass>> classes = module_->GetClasses();
  157. for (unsigned i = 0; i < classes.Size(); i++)
  158. {
  159. JSBClass* klass = classes.At(i);
  160. if (klass->IsNumberArray())
  161. continue;
  162. CSClassWriter clsWriter(klass);
  163. clsWriter.GenerateManagedSource(source);
  164. }
  165. }
  166. void CSModuleWriter::GenerateManagedEnumsAndConstants(String& source)
  167. {
  168. Vector<SharedPtr<JSBEnum>> enums = module_->enums_.Values();
  169. Indent();
  170. for (unsigned i = 0; i < enums.Size(); i++)
  171. {
  172. JSBEnum* jenum = enums[i];
  173. source += "\n";
  174. String line = "public enum " + jenum->GetName() + "\n";
  175. source += IndentLine(line);
  176. source += IndentLine("{\n");
  177. HashMap<String, String>& values = jenum->GetValues();
  178. HashMap<String, String>::ConstIterator itr = values.Begin();
  179. Indent();
  180. while (itr != values.End())
  181. {
  182. String name = (*itr).first_;
  183. String value = (*itr).second_;
  184. // BodyType2D enum order is assigned in RigidBody2D.h in incorrect order
  185. if (jenum->GetName() == "BodyType2D")
  186. {
  187. if (name == "BT_STATIC")
  188. value = "0";
  189. else if (name == "BT_KINEMATIC")
  190. value = "1";
  191. else if (name == "BT_DYNAMIC")
  192. value = "2";
  193. }
  194. if (value.Length())
  195. {
  196. line = name + " = " + value;
  197. }
  198. else
  199. {
  200. line = name;
  201. }
  202. itr++;
  203. if (itr != values.End())
  204. line += ",";
  205. line += "\n";
  206. source += IndentLine(line);
  207. }
  208. Dedent();
  209. source += IndentLine("}\n");
  210. }
  211. // constants
  212. HashMap<String, JSBModule::Constant>& constants = module_->GetConstants();
  213. if (constants.Size())
  214. {
  215. source += "\n";
  216. String line = "public static partial class Constants\n";
  217. source += IndentLine(line);
  218. source += IndentLine("{\n");
  219. const Vector<String>& constantsName = constants.Keys();
  220. Indent();
  221. for (unsigned i = 0; i < constantsName.Size(); i++)
  222. {
  223. const String& cname = constantsName.At(i);
  224. JSBModule::Constant& constant = constants[cname];
  225. String managedType = GetManagedPrimitiveType(constant.type);
  226. String value = constant.value;
  227. if (!value.Length())
  228. continue;
  229. //static const unsigned M_MIN_UNSIGNED = 0x00000000;
  230. // /static const unsigned M_MAX_UNSIGNED = 0xffffffff;
  231. if (cname == "M_MIN_INT")
  232. value = "int.MinValue";
  233. if (cname == "M_INFINITY")
  234. value = "float.MaxValue";
  235. if (value == "M_MAX_UNSIGNED")
  236. value = "0xffffffff";
  237. // Input stuff
  238. if (module_->GetName() == "Input")
  239. {
  240. if (cname.StartsWith("KEY_"))
  241. {
  242. if (value.Length() == 1 && (IsAlpha(value[0]) || IsDigit(value[0])))
  243. value = "'" + value + "'";
  244. }
  245. // https://raw.githubusercontent.com/flibitijibibo/SDL2-CS/master/src/SDL2.cs
  246. if (value.StartsWith("SDL_BUTTON_") || value.StartsWith("SDL_HAT_"))
  247. {
  248. value = "(int) SDL." + value;
  249. }
  250. else if (value.StartsWith("SDLK_"))
  251. {
  252. value = "(int) SDL.SDL_Keycode." + value;
  253. }
  254. else if (value.StartsWith("SDL_SCANCODE_"))
  255. {
  256. value = "(int) SDL.SDL_Scancode." + value;
  257. }
  258. else if (value.StartsWith("SDL_CONTROLLER_BUTTON_"))
  259. {
  260. value = "(int) SDL.SDL_GameControllerButton." + value;
  261. }
  262. else if (value.StartsWith("SDL_CONTROLLER_AXIS_"))
  263. {
  264. value = "(int) SDL.SDL_GameControllerAxis." + value;
  265. }
  266. }
  267. String line = "public const " + managedType + " " + cname + " = " + value;
  268. if (managedType == "float" && !line.EndsWith("f") && IsDigit(line[line.Length()-1]))
  269. line += "f";
  270. line += ";\n";
  271. source += IndentLine(line);
  272. }
  273. Dedent();
  274. source += "\n";
  275. line = "}\n";
  276. source += IndentLine(line);
  277. }
  278. source += "\n";
  279. Dedent();
  280. }
  281. void CSModuleWriter::GenerateManagedNativeEvents(String& sourceOut)
  282. {
  283. Indent();
  284. String source;
  285. const Vector<SharedPtr<JSBEvent>>& events = module_->GetEvents();
  286. for (unsigned i = 0; i < events.Size(); i++)
  287. {
  288. JSBEvent* event = events[i];
  289. const String& eventID = event->GetEventID();
  290. String line = ToString("public partial class %s : NativeEventData\n", event->GetScriptEventName().CString());
  291. source += IndentLine(line);
  292. source += IndentLine("{\n\n");
  293. Indent();
  294. // parameters
  295. const Vector<JSBEvent::EventParam>& params = event->GetParameters();
  296. for (unsigned j = 0; j < params.Size(); j++)
  297. {
  298. const JSBEvent::EventParam& p = params[j];
  299. JSBClass* cls = JSBPackage::GetClassAllPackages(p.typeInfo_);
  300. String typeName = p.typeInfo_;
  301. String enumTypeName = p.enumTypeName_;
  302. if (!cls)
  303. typeName = typeName.ToLower();
  304. else
  305. typeName = cls->GetName();
  306. if (typeName == "int" || typeName == "float" ||
  307. typeName == "bool" || typeName == "string" || typeName == "enum" || cls)
  308. {
  309. bool isEnum = false;
  310. if (typeName == "enum")
  311. {
  312. isEnum = true;
  313. if (enumTypeName.Length())
  314. typeName = enumTypeName;
  315. else
  316. typeName = "int";
  317. }
  318. line = "public " + typeName + " " + p.paramName_ + "\n";
  319. source += IndentLine(line);
  320. source += IndentLine("{\n");
  321. Indent();
  322. source += IndentLine("get\n");
  323. source += IndentLine("{\n");
  324. Indent();
  325. line = "return ";
  326. if (typeName == "int")
  327. line += "scriptMap.GetInt";
  328. else if (isEnum)
  329. {
  330. line += ToString("(%s) scriptMap.GetInt", typeName.CString());
  331. }
  332. else if (typeName == "float")
  333. line += "scriptMap.GetFloat";
  334. else if (typeName == "bool")
  335. line += "scriptMap.GetBool";
  336. else if (typeName == "string")
  337. line += "scriptMap.GetString";
  338. else if (cls)
  339. {
  340. if (typeName == "Vector3")
  341. {
  342. line += "scriptMap.Get" + typeName;
  343. }
  344. else
  345. {
  346. line += ToString("scriptMap.GetPtr<%s>", cls->GetName().CString());
  347. }
  348. }
  349. line += ToString("(\"%s\");\n", p.paramName_.CString());
  350. source += IndentLine(line);
  351. Dedent();
  352. source += IndentLine("}\n");
  353. Dedent();
  354. source += IndentLine("}\n\n");
  355. }
  356. }
  357. Dedent();
  358. source += IndentLine("}\n\n");
  359. }
  360. sourceOut += source;
  361. Dedent();
  362. }
  363. void CSModuleWriter::GenerateManagedModuleClass(String& sourceOut)
  364. {
  365. Indent();
  366. String source;
  367. String line = ToString("public static partial class %sModule\n", module_->GetName().CString());
  368. source += IndentLine(line);
  369. source += IndentLine("{\n");
  370. Indent();
  371. source += IndentLine("public static void Initialize()\n");
  372. source += IndentLine("{\n");
  373. Indent();
  374. Vector<SharedPtr<JSBClass>> classes = module_->GetClasses();
  375. for (unsigned i = 0; i < classes.Size(); i++)
  376. {
  377. JSBClass* klass = classes.At(i);
  378. JSBPackage* package = module_->GetPackage();
  379. if (klass->IsNumberArray() || klass->IsAbstract())
  380. continue;
  381. const char* className = klass->GetName().CString();
  382. String classGuard = module_->GetClassDefineGuard(classes[i]->GetNativeName(), "csharp");
  383. if (classGuard.Length())
  384. {
  385. source += ToString("\n%s\n", classGuard.CString());
  386. }
  387. line = ToString("new NativeType(%s.csb_%s_%s_GetClassIDStatic (), ", className, package->GetName().CString(), className);
  388. line += ToString("typeof(%s), (IntPtr x) => { return new %s (x); } );\n",className, className);
  389. source += IndentLine(line);
  390. if (classGuard.Length())
  391. {
  392. source += ToString("#endif\n", classGuard.CString());
  393. }
  394. }
  395. source += "\n";
  396. // Native Events
  397. const Vector<SharedPtr<JSBEvent>>& events = module_->GetEvents();
  398. for (unsigned i = 0; i < events.Size(); i++)
  399. {
  400. JSBEvent* event = events[i];
  401. line = ToString("NativeEvents.RegisterEventID<%s>(\"%s\");\n", event->GetScriptEventName().CString(), event->GetEventName().CString());
  402. source += IndentLine(line);
  403. }
  404. Dedent();
  405. source += IndentLine("}\n");
  406. Dedent();
  407. source += IndentLine("}\n");
  408. sourceOut += source;
  409. Dedent();
  410. }
  411. void CSModuleWriter::GenerateManagedSource()
  412. {
  413. String source = "// Autogenerated";
  414. String moduleName = module_->GetPackage()->GetNamespace();
  415. source += "\nusing System;\nusing System.Collections.Generic;\nusing System.Runtime.InteropServices;\nusing static System.Reflection.IntrospectionExtensions;\n";
  416. if (moduleName == "Atomic")
  417. moduleName = "AtomicEngine";
  418. if (moduleName != "AtomicEngine")
  419. {
  420. source += "using AtomicEngine;\n";
  421. }
  422. source += "\n\n";
  423. source += "namespace " + moduleName + "\n";
  424. source += "{\n";
  425. GenerateManagedEnumsAndConstants(source);
  426. GenerateManagedNativeEvents(source);
  427. GenerateManagedModuleClass(source);
  428. GenerateManagedClasses(source);
  429. source += "}\n";
  430. JSBind* jsbind = module_->GetSubsystem<JSBind>();
  431. String filepath = jsbind->GetDestScriptFolder() + "/CSModule" + module_->name_ + ".cs";
  432. File file(module_->GetContext());
  433. file.Open(filepath, FILE_WRITE);
  434. file.Write(source.CString(), source.Length());
  435. file.Close();
  436. }
  437. void CSModuleWriter::GenerateSource()
  438. {
  439. GenerateNativeSource();
  440. GenerateManagedSource();
  441. }
  442. }