CSModuleWriter.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. //
  2. // Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
  3. // LICENSE: Atomic Game Engine Editor and Tools EULA
  4. // Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for
  5. // license information: https://github.com/AtomicGameEngine/AtomicGameEngine
  6. //
  7. #include <Atomic/IO/File.h>
  8. #include <Atomic/IO/FileSystem.h>
  9. #include "../JSBind.h"
  10. #include "../JSBPackage.h"
  11. #include "../JSBModule.h"
  12. #include "../JSBEnum.h"
  13. #include "../JSBClass.h"
  14. #include "../JSBFunction.h"
  15. #include "CSTypeHelper.h"
  16. #include "CSClassWriter.h"
  17. #include "CSModuleWriter.h"
  18. namespace ToolCore
  19. {
  20. CSModuleWriter::CSModuleWriter(JSBModule *module) : JSBModuleWriter(module)
  21. {
  22. }
  23. void CSModuleWriter::WriteIncludes(String& source)
  24. {
  25. Vector<String>& includes = module_->includes_;
  26. for (unsigned i = 0; i < includes.Size(); i++)
  27. {
  28. if (includes[i].StartsWith("<"))
  29. source.AppendWithFormat("#include %s\n", includes[i].CString());
  30. else
  31. source.AppendWithFormat("#include \"%s\"\n", includes[i].CString());
  32. }
  33. Vector<JSBHeader*> allheaders;
  34. HashMap<StringHash, SharedPtr<JSBEnum> >::Iterator eitr = module_->enums_.Begin();
  35. while (eitr != module_->enums_.End())
  36. {
  37. allheaders.Push(eitr->second_->GetHeader());
  38. eitr++;
  39. }
  40. HashMap<StringHash, SharedPtr<JSBClass> >::Iterator citr = module_->classes_.Begin();
  41. while (citr != module_->classes_.End())
  42. {
  43. allheaders.Push(citr->second_->GetHeader());
  44. citr++;
  45. }
  46. Vector<JSBHeader*> included;
  47. for (unsigned i = 0; i < allheaders.Size(); i++)
  48. {
  49. JSBHeader* header = allheaders.At(i);
  50. if (included.Contains(header))
  51. continue;
  52. String headerPath = GetPath(header->GetFilePath());
  53. String headerfile = GetFileNameAndExtension(header->GetFilePath());
  54. JSBind* jsbind = header->GetSubsystem<JSBind>();
  55. headerPath.Replace(jsbind->GetSourceRootFolder() + "Source/", "");
  56. source.AppendWithFormat("#include <%s%s>\n", headerPath.CString(), headerfile.CString());
  57. included.Push(header);
  58. }
  59. source += ToString("\n#include \"CSPackage%s.h\"\n", module_->GetPackage()->GetName().CString());
  60. }
  61. void CSModuleWriter::GenerateNativeThunkInit(String& sourceOut)
  62. {
  63. const char* packageName = module_->GetPackage()->GetName().CString();
  64. const char* moduleName = module_->GetName().CString();
  65. String source, line;
  66. String thunkName = ToString("AtomicNET%sThunk",packageName);
  67. source.AppendWithFormat("\nvoid csb_package_%s_init_%s_thunk ()\n{\n\n", packageName, moduleName);
  68. Vector<SharedPtr<JSBClass>> classes = module_->classes_.Values();
  69. Indent();
  70. for (unsigned i = 0; i < classes.Size(); i++)
  71. {
  72. JSBClass* cls = classes[i];
  73. if (cls->IsNumberArray())
  74. continue;
  75. PODVector<JSBFunction*> functions = cls->GetFunctions();
  76. for (unsigned j = 0; j < functions.Size(); j++)
  77. {
  78. JSBFunction* function = functions[j];
  79. if (CSTypeHelper::OmitFunction(function))
  80. continue;
  81. line = ToString("%s.__%s_%s_%s = ", thunkName.CString(), packageName, cls->GetName().CString(),
  82. function->IsConstructor() ? "Constructor" : function->GetName().CString());
  83. line += ToString("csb_%s_%s_%s;\n", packageName, cls->GetName().CString(),
  84. function->IsConstructor() ? "Constructor" : function->GetName().CString());
  85. source += IndentLine(line);
  86. }
  87. }
  88. Dedent();
  89. source += "\n}\n";
  90. sourceOut += source;
  91. }
  92. void CSModuleWriter::GenerateNativeSource()
  93. {
  94. String source = "// This file was autogenerated by JSBind, changes will be lost\n";
  95. source += "#ifdef ATOMIC_PLATFORM_WINDOWS\n";
  96. source += "#pragma warning(disable: 4244) // possible loss of data\n";
  97. source += "#define ATOMIC_EXPORT_API __declspec(dllexport)\n";
  98. source += "#else\n";
  99. source += "#define ATOMIC_EXPORT_API\n";
  100. source += "#endif\n";
  101. if (module_->Requires("3D"))
  102. {
  103. source += "#ifdef ATOMIC_3D\n";
  104. }
  105. WriteIncludes(source);
  106. source += "\n#include <AtomicNET/NETCore/NETCore.h>\n";
  107. String ns = module_->GetPackage()->GetNamespace();
  108. source += "\n\nusing namespace " + ns + ";\n\n";
  109. source += "\n\nextern \"C\" \n{\n \n";
  110. source += "// Begin Class Declarations\n";
  111. source += "// End Class Declarations\n\n";
  112. source += "// Begin Classes\n";
  113. Vector<SharedPtr<JSBClass>> classes = module_->classes_.Values();
  114. for (unsigned i = 0; i < classes.Size(); i++)
  115. {
  116. CSClassWriter clsWriter(classes[i]);
  117. clsWriter.GenerateNativeSource(source);
  118. }
  119. source += "// End Classes\n\n";
  120. GenerateNativeThunkInit(source);
  121. // end Atomic namespace
  122. source += "\n}\n";
  123. if (module_->Requires("3D"))
  124. {
  125. source += "#endif //ATOMIC_3D\n";
  126. }
  127. JSBind* jsbind = module_->GetSubsystem<JSBind>();
  128. String filepath = jsbind->GetDestNativeFolder() + "/CSModule" + module_->name_ + ".cpp";
  129. File file(module_->GetContext());
  130. file.Open(filepath, FILE_WRITE);
  131. file.Write(source.CString(), source.Length());
  132. file.Close();
  133. }
  134. String CSModuleWriter::GetManagedPrimitiveType(JSBPrimitiveType* ptype)
  135. {
  136. if (ptype->kind_ == JSBPrimitiveType::Bool)
  137. return "bool";
  138. if (ptype->kind_ == JSBPrimitiveType::Int && ptype->isUnsigned_)
  139. return "uint";
  140. else if (ptype->kind_ == JSBPrimitiveType::Int)
  141. return "int";
  142. if (ptype->kind_ == JSBPrimitiveType::Float)
  143. return "float";
  144. return "int";
  145. }
  146. void CSModuleWriter::GenerateManagedClasses(String& source)
  147. {
  148. Vector<SharedPtr<JSBClass>> classes = module_->classes_.Values();
  149. for (unsigned i = 0; i < classes.Size(); i++)
  150. {
  151. JSBClass* klass = classes.At(i);
  152. if (klass->IsNumberArray())
  153. continue;
  154. CSClassWriter clsWriter(klass);
  155. clsWriter.GenerateManagedSource(source);
  156. }
  157. }
  158. void CSModuleWriter::GenerateManagedEnumsAndConstants(String& source)
  159. {
  160. Vector<SharedPtr<JSBEnum>> enums = module_->enums_.Values();
  161. Indent();
  162. for (unsigned i = 0; i < enums.Size(); i++)
  163. {
  164. JSBEnum* jenum = enums[i];
  165. source += "\n";
  166. String line = "public enum " + jenum->GetName() + "\n";
  167. source += IndentLine(line);
  168. source += IndentLine("{\n");
  169. HashMap<String, String>& values = jenum->GetValues();
  170. HashMap<String, String>::ConstIterator itr = values.Begin();
  171. Indent();
  172. while (itr != values.End())
  173. {
  174. String name = (*itr).first_;
  175. String value = (*itr).second_;
  176. if (value.Length())
  177. {
  178. line = name + " = " + value;
  179. }
  180. else
  181. {
  182. line = name;
  183. }
  184. itr++;
  185. if (itr != values.End())
  186. line += ",";
  187. line += "\n";
  188. source += IndentLine(line);
  189. }
  190. Dedent();
  191. source += IndentLine("}\n");
  192. }
  193. // constants
  194. HashMap<String, JSBModule::Constant>& constants = module_->GetConstants();
  195. if (constants.Size())
  196. {
  197. source += "\n";
  198. String line = "public static partial class Constants\n";
  199. source += IndentLine(line);
  200. source += IndentLine("{\n");
  201. const Vector<String>& constantsName = constants.Keys();
  202. Indent();
  203. for (unsigned i = 0; i < constantsName.Size(); i++)
  204. {
  205. const String& cname = constantsName.At(i);
  206. JSBModule::Constant& constant = constants[cname];
  207. String managedType = GetManagedPrimitiveType(constant.type);
  208. String value = constant.value;
  209. if (!value.Length())
  210. continue;
  211. //static const unsigned M_MIN_UNSIGNED = 0x00000000;
  212. // /static const unsigned M_MAX_UNSIGNED = 0xffffffff;
  213. if (value == "M_MAX_UNSIGNED")
  214. value = "0xffffffff";
  215. // Input stuff
  216. if (module_->GetName() == "Input")
  217. {
  218. if (cname.StartsWith("KEY_"))
  219. {
  220. if (value.Length() == 1 && (IsAlpha(value[0]) || IsDigit(value[0])))
  221. value = "'" + value + "'";
  222. }
  223. // https://raw.githubusercontent.com/flibitijibibo/SDL2-CS/master/src/SDL2.cs
  224. if (value.StartsWith("SDL_BUTTON_") || value.StartsWith("SDL_HAT_"))
  225. {
  226. value = "(int) SDL." + value;
  227. }
  228. else if (value.StartsWith("SDLK_"))
  229. {
  230. value = "(int) SDL.SDL_Keycode." + value;
  231. }
  232. else if (value.StartsWith("SDL_SCANCODE_"))
  233. {
  234. value = "(int) SDL.SDL_Scancode." + value;
  235. }
  236. else if (value.StartsWith("SDL_CONTROLLER_BUTTON_"))
  237. {
  238. value = "(int) SDL.SDL_GameControllerButton." + value;
  239. }
  240. else if (value.StartsWith("SDL_CONTROLLER_AXIS_"))
  241. {
  242. value = "(int) SDL.SDL_GameControllerAxis." + value;
  243. }
  244. }
  245. String line = "public const " + managedType + " " + cname + " = " + value;
  246. if (managedType == "float" && !line.EndsWith("f"))
  247. line += "f";
  248. line += ";\n";
  249. source += IndentLine(line);
  250. }
  251. Dedent();
  252. source += "\n";
  253. line = "}\n";
  254. source += IndentLine(line);
  255. }
  256. source += "\n";
  257. Dedent();
  258. }
  259. void CSModuleWriter::GenerateManagedModuleClass(String& sourceOut)
  260. {
  261. Indent();
  262. String source;
  263. String line = ToString("public static partial class %sModule\n", module_->GetName().CString());
  264. source += IndentLine(line);
  265. source += IndentLine("{\n");
  266. Indent();
  267. source += IndentLine("public static void Initialize()\n");
  268. source += IndentLine("{\n");
  269. Indent();
  270. Vector<SharedPtr<JSBClass>> classes = module_->classes_.Values();
  271. for (unsigned i = 0; i < classes.Size(); i++)
  272. {
  273. JSBClass* klass = classes.At(i);
  274. JSBPackage* package = module_->GetPackage();
  275. if (klass->IsNumberArray() || klass->IsAbstract())
  276. continue;
  277. line = ToString("NativeCore.RegisterNativeType(typeof(%s));\n", klass->GetName().CString());
  278. source += IndentLine(line);
  279. line = ToString("NativeCore.nativeClassIDToManagedConstructor [ %s.csb_%s_%s_GetClassIDStatic ()] = (IntPtr x) => {\n",
  280. klass->GetName().CString(), package->GetName().CString(), klass->GetName().CString());
  281. source += IndentLine(line);
  282. Indent();
  283. source += IndentLine(ToString("return new %s (x);\n", klass->GetName().CString()));
  284. Dedent();
  285. source += IndentLine("};\n");
  286. }
  287. Dedent();
  288. source += IndentLine("}\n");
  289. Dedent();
  290. source += IndentLine("}\n");
  291. sourceOut += source;
  292. Dedent();
  293. }
  294. void CSModuleWriter::GenerateManagedSource()
  295. {
  296. String source = "// Autogenerated";
  297. String moduleName = module_->GetPackage()->GetName();
  298. source += "\nusing System;\nusing System.Collections.Generic;\nusing System.Runtime.InteropServices;\n";
  299. if (moduleName == "Atomic")
  300. moduleName = "AtomicEngine";
  301. if (moduleName != "AtomicEngine")
  302. {
  303. source += "using AtomicEngine;\n";
  304. }
  305. source += "\n\n";
  306. source += "namespace " + moduleName + "\n";
  307. source += "{\n";
  308. GenerateManagedEnumsAndConstants(source);
  309. GenerateManagedModuleClass(source);
  310. GenerateManagedClasses(source);
  311. source += "}\n";
  312. JSBind* jsbind = module_->GetSubsystem<JSBind>();
  313. String filepath = jsbind->GetDestScriptFolder() + "/CSModule" + module_->name_ + ".cs";
  314. File file(module_->GetContext());
  315. file.Open(filepath, FILE_WRITE);
  316. file.Write(source.CString(), source.Length());
  317. file.Close();
  318. }
  319. void CSModuleWriter::GenerateSource()
  320. {
  321. GenerateNativeSource();
  322. GenerateManagedSource();
  323. }
  324. }