PageRenderTime 58ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/Wrapper Generators/ConverterLibrary/ClassTranslator.cpp

http://rootdotnet.codeplex.com
C++ | 1962 lines | 1236 code | 314 blank | 412 comment | 298 complexity | 7370052cc25535ff16d7e959c5fb1221 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. #include "ClassTranslator.hpp"
  2. #include "SourceEmitter.hpp"
  3. #include "RootClassInfo.hpp"
  4. #include "RootClassInfoCollection.hpp"
  5. #include "RootClassMethod.hpp"
  6. #include "CPPNetTypeMapper.hpp"
  7. #include "RootClassMethodArg.hpp"
  8. #include "WrapperConfigurationInfo.hpp"
  9. #include "ROOTHelpers.h"
  10. #include "ConverterErrorLog.hpp"
  11. #include "FeatureManager.hpp"
  12. #include "TROOT.h"
  13. #include "TClass.h"
  14. #include <algorithm>
  15. #include <sstream>
  16. #include <fstream>
  17. #include <vector>
  18. #include <iostream>
  19. #include <set>
  20. #include <stdio.h>
  21. #include <stdexcept>
  22. using std::ostringstream;
  23. using std::endl;
  24. using std::cout;
  25. using std::ofstream;
  26. using std::ifstream;
  27. using std::vector;
  28. using std::string;
  29. using std::runtime_error;
  30. using std::set;
  31. using std::for_each;
  32. using std::map;
  33. using std::pair;
  34. using std::string;
  35. using std::getline;
  36. using std::transform;
  37. using std::back_inserter;
  38. using std::inserter;
  39. #ifdef nullptr
  40. #undef nullptr
  41. #endif
  42. ClassTranslator::ClassTranslator(const std::string &base_dir)
  43. : _base_directory (base_dir)
  44. {
  45. load_globals();
  46. _default_header_includes.push_back ("NetArrayTranslator.hpp");
  47. _default_header_includes.push_back ("VectorObject.hpp");
  48. }
  49. ClassTranslator::~ClassTranslator(void)
  50. {
  51. }
  52. /// Drives the translation of a class
  53. void ClassTranslator::translate(RootClassInfo &class_info)
  54. {
  55. ///
  56. /// Clean up the class inheritance list. And make sure that everything is well in there. If this fails, then
  57. /// we need fail hard b/c others might be depending on this class being translated.
  58. ///
  59. clean_inheritance_list (class_info);
  60. if (!check_inheritance_list(class_info)) {
  61. throw new runtime_error ("Class '" + class_info.CPPName() + "' has some bad classes in its inherritance tree");
  62. }
  63. ///
  64. /// create the template around the outside
  65. ///
  66. ostringstream cpp_filename, hpp_filename;
  67. cpp_filename << _base_directory << "\\" << class_info.NETName() << ".cpp";
  68. hpp_filename << _base_directory << "\\" << class_info.NETName() << ".hpp";
  69. SourceEmitter cpp_emitter (cpp_filename.str());
  70. SourceEmitter hpp_emitter (hpp_filename.str());
  71. cpp_emitter() << "// Generated by ROOT Wrapper Generator" << endl;
  72. hpp_emitter() << "// Generated by ROOT Wrapper Generator" << endl;
  73. hpp_emitter() << "#pragma once" << endl;
  74. cpp_emitter.include_file(class_info.NETName() + ".hpp");
  75. // HACK Horrible hack: this is because some standalone files require this in order to build (TAttLine, etc.)!
  76. hpp_emitter.start_line() << "/// Hack to deal with some include files requiring iostream and std to be defined" << endl;
  77. hpp_emitter.include_file("iostream");
  78. hpp_emitter.start_line() << "using namespace std;" << endl;
  79. ///
  80. /// The include file for the ROOT object itself
  81. ///
  82. hpp_emitter.include_file(class_info.include_filename());
  83. ///
  84. /// Now, we want every possible method accessible outside the C++ world. The current C++ compiler will make methods
  85. /// that have raw C++ objects inaccessible outside the library (but accessible within the library). This way, if someone
  86. /// has to do somethign down and dirty in C++ they can do it without having to hack the code we generate.
  87. ///
  88. /// Because multiple objects can be defined in one file, we have to make sure all make_public's are issued for the objects
  89. /// in that one file. Crazyness. So, we write a seperate include file which all headers include for their header.
  90. /// Note that we write out the seperate file here. Most files will be written once (since the header files contain
  91. /// only a single object), but some will be written twice. We can do that or make this a lot more complex! :-)
  92. ///
  93. hpp_emitter.start_line() << "/// Make sure all native objects are accessible outside the boundries of this library/dll" << endl;
  94. hpp_emitter.include_file(class_info.LibraryName() + "-make_public.hpp");
  95. _objects_in_library[class_info.LibraryName()].insert(class_info.CPPName());
  96. _base_directories[class_info.LibraryName()] = _base_directory;
  97. ///
  98. /// If we have a non-TObject, then we will be needing TClass...
  99. ///
  100. if (!class_info.InheritsFromTObject() && class_info.CPPName() != "TObject")
  101. {
  102. hpp_emitter.include_file("TClass.h");
  103. }
  104. ///
  105. /// And the include files for all the interfaces that we will be referencing.
  106. /// Mark these guys as a dependencies as well, as we will need them in order to
  107. /// build!
  108. ///
  109. /// Note that the includes between libraries aren't strictly needed. That is -- if we are building these objects in
  110. /// different libraries then it really doesn't matter if we do the include (it does matter within the same library,
  111. /// however). But we treat all objects as the same -- and go overboard with the includes -- because that makes this
  112. /// bit of code cleaner, and (I hope) doen't slow down the resulting build very much.
  113. ///
  114. for (unsigned int i = 0; i < class_info.GetDirectInheritedClasses().size(); i++) {
  115. RootClassInfo &dep_class(RootClassInfoCollection::GetRootClassInfo(class_info.GetDirectInheritedClasses()[i]));
  116. if (emit_this_header(class_info, dep_class)) {
  117. hpp_emitter.include_file(dep_class.NETName() + ".hpp");
  118. }
  119. if (class_info.LibraryName() != dep_class.LibraryName()) {
  120. _library_dependencies[class_info.LibraryName()].insert(dep_class.LibraryName());
  121. }
  122. }
  123. set<string> referenced_classes;
  124. copy (class_info.GetReferencedClasses().begin(), class_info.GetReferencedClasses().end(),
  125. inserter(referenced_classes, referenced_classes.begin()));
  126. auto featureClasses = FeatureManager::GetFeaturesFor(class_info).get_additional_root_class_references(class_info);
  127. copy (featureClasses.begin(), featureClasses.end(), inserter(referenced_classes, referenced_classes.begin()));
  128. vector<string> v_referenced_classes (referenced_classes.begin(), referenced_classes.end());
  129. for (unsigned int i = 0; i < v_referenced_classes.size(); i++) {
  130. RootClassInfo &dep_class(RootClassInfoCollection::GetRootClassInfo(v_referenced_classes[i]));
  131. if (CPPNetTypeMapper::instance()->has_mapping(dep_class.CPPName())) {
  132. if (emit_this_header(class_info, dep_class)) {
  133. cpp_emitter.include_file(dep_class.NETName() + ".hpp");
  134. } else {
  135. cpp_emitter.include_file(dep_class.include_filename());
  136. }
  137. if (class_info.LibraryName() != dep_class.LibraryName()) {
  138. _library_dependencies[class_info.LibraryName()].insert(dep_class.LibraryName());
  139. }
  140. }
  141. }
  142. for (unsigned int i = 0; i < class_info.GetReferencedEnums().size(); i++) {
  143. RootEnum dep_enum (class_info.GetReferencedEnums()[i]);
  144. if (CPPNetTypeMapper::instance()->has_mapping(dep_enum.NameQualified())) {
  145. if (!emit_this_enum(class_info, dep_enum)) {
  146. cpp_emitter.include_file(dep_enum.include_filename());
  147. }
  148. }
  149. }
  150. ///
  151. /// Always enable the referencing of arrays
  152. ///
  153. emit_hpp_headers(hpp_emitter);
  154. ///
  155. /// We use exceptions...
  156. ///
  157. cpp_emitter.include_file("stdexcept");
  158. ///
  159. /// Enum's can't be forward declared -- they have to be included... If they are class enums, however, then
  160. /// they should just come in. If they are in other libraries, then they will be pulled in with the reference.
  161. /// The trick comes b/c if they are defined in the library we are working on right now, then they will have to
  162. /// be included. Ugh.
  163. ///
  164. for (unsigned int i = 0; i < class_info.GetReferencedEnums().size(); i++) {
  165. RootEnum dep_enum (class_info.GetReferencedEnums()[i]);
  166. if (CPPNetTypeMapper::instance()->has_mapping(dep_enum.NameQualified())) {
  167. if (!dep_enum.IsClassDefined()) {
  168. if (emit_this_enum(class_info, dep_enum)) {
  169. hpp_emitter.include_file(dep_enum.NameUnqualified() + ".hpp");
  170. }
  171. } else {
  172. if (dep_enum.LibraryName() == class_info.LibraryName()) {
  173. if (dep_enum.NETClassName() != class_info.NETName()) {
  174. hpp_emitter.include_file(dep_enum.NETClassName() + ".hpp");
  175. }
  176. }
  177. }
  178. }
  179. }
  180. ///
  181. /// Put everything in a ROOT namespace to keep it clean...
  182. ///
  183. hpp_emitter.start_namespace ("ROOTNET");
  184. cpp_emitter.start_namespace ("ROOTNET");
  185. ///
  186. /// Forward declare the various .net classes we might be referencing in the
  187. /// header...
  188. ///
  189. for (unsigned int i = 0; i < class_info.GetReferencedClasses().size(); i++) {
  190. string referenced_classname = class_info.GetReferencedClasses()[i];
  191. if (CPPNetTypeMapper::instance()->has_mapping(referenced_classname)) {
  192. hpp_emitter.forward_class_reference(RootClassInfoCollection::GetRootClassInfo(referenced_classname).NETName());
  193. }
  194. }
  195. ///
  196. /// Generate the interface and the actual class
  197. ///
  198. generate_interface (class_info, hpp_emitter);
  199. generate_class_methods (class_info, cpp_emitter);
  200. generate_interface_static_methods (class_info, cpp_emitter);
  201. generate_class_header (class_info, hpp_emitter);
  202. ///
  203. /// Now the full on object.
  204. ///
  205. hpp_emitter.brace_close();
  206. cpp_emitter.brace_close();
  207. ///
  208. /// Close everything up so we can get on with things
  209. ///
  210. hpp_emitter.close();
  211. cpp_emitter.close();
  212. }
  213. void ClassTranslator::emit_hpp_headers(SourceEmitter &hpp_emitter)
  214. {
  215. for (int i = 0; i < _default_header_includes.size(); i++) {
  216. hpp_emitter.include_file(_default_header_includes[i]);
  217. }
  218. }
  219. /// Helper class to dump out the make public files.
  220. class write_out_make_public
  221. {
  222. public:
  223. inline write_out_make_public (const map<string, string> base_directories)
  224. : _base_directory(base_directories)
  225. {
  226. }
  227. void operator() (const pair<string, set<string> > &item);
  228. private:
  229. const map<string, string> _base_directory;
  230. };
  231. ///
  232. /// Write out all the make-public statements and forward declare all the classes. We do this to uniformly expose all the
  233. /// various items to other libraries.
  234. ///
  235. void ClassTranslator::finalize_make_publics()
  236. {
  237. for_each (_objects_in_library.begin(), _objects_in_library.end(),
  238. write_out_make_public(_base_directories));
  239. }
  240. void write_out_make_public::operator ()(const std::pair<string,set<string> > &item)
  241. {
  242. string library_name (item.first);
  243. set<string> all_objects_set (item.second);
  244. ostringstream make_public_filename;
  245. map<string, string>::const_iterator dir_loc = _base_directory.find(library_name);
  246. if (dir_loc == _base_directory.end()) {
  247. throw runtime_error ("Unable to find base directory for library " + library_name);
  248. }
  249. make_public_filename << dir_loc->second << "\\" << library_name << "-make_public.hpp";
  250. SourceEmitter make_public_header (make_public_filename.str());
  251. make_public_header.start_line() << "#pragma once" << endl;
  252. make_public_header.start_line() << "// List of the objects defined in this library, tagged with make_public" << endl;
  253. vector<string> all_objects(all_objects_set.begin(), all_objects_set.end());
  254. for (unsigned int i = 0; i < all_objects.size(); i++) {
  255. make_public_header.start_line() << "class " << all_objects[i] << ";" << endl;
  256. make_public_header.start_line() << "#pragma make_public(" << all_objects[i] << ")" << endl;
  257. }
  258. make_public_header.close();
  259. }
  260. namespace {
  261. /// Indexers -- using the [] operators in C++ -- are a tried and true way of getting and setting
  262. /// elements inside an array like object. .NET supports this in the form of "indexers" -- but
  263. /// they require a "get" and a "set" method, and you don't use a reference. So we have to sort
  264. /// through the C++ code and see if we can tease all that information out.
  265. /// Store info about the operator[] pairs that are out there.
  266. class CPPIndexerInfo
  267. {
  268. public:
  269. /// Translators to represent the C++/.NET arguments.
  270. const CPPNetTypeMapper::TypeTranslator *_index_type;
  271. const CPPNetTypeMapper::TypeTranslator * _return_type;
  272. /// The method this is based on
  273. const RootClassMethod *_method;
  274. /// True if this has a get and a set (you can set the internal value). You can always get it...
  275. bool _is_setter;
  276. inline CPPIndexerInfo (void)
  277. : _is_setter(false), _index_type(0), _return_type(0)
  278. {}
  279. };
  280. /// Helper task to convert a map into a vector. Just makes code below
  281. /// prettier.
  282. template<class C>
  283. class copy_map_target_t
  284. {
  285. public:
  286. template<class I>
  287. inline void operator() (const pair<I,C> &item)
  288. {
  289. _vector.push_back(item.second);
  290. }
  291. inline const vector<C> &as_vector(void) const
  292. {
  293. return _vector;
  294. }
  295. private:
  296. vector<C> _vector;
  297. };
  298. /// Given a list of indexers, try to find all the ones that match up.
  299. vector<CPPIndexerInfo> SortIndexers(const vector<RootClassMethod> &index_list)
  300. {
  301. map<string, CPPIndexerInfo> result_map;
  302. for (int i = 0; i < index_list.size(); i++) {
  303. const RootClassMethod &method(index_list[i]);
  304. /// Figure out what this guy is
  305. string return_type = method.return_type();
  306. if (method.arguments().size() != 1) {
  307. ConverterErrorLog::log_type_error(method.ClassOfMethodDefinition(),
  308. "Indexer with return type " + return_type + " does not have a single argument!");
  309. continue;
  310. }
  311. const string index_argument = method.arguments()[0].NETInterfaceTypeName();
  312. /// Look for clues in the return type to see what the ROOT Dev team wanted to do with this.
  313. bool has_const = false;
  314. bool has_reference = false;
  315. bool is_abs_class = false;
  316. if (return_type.find("const ") == 0) {
  317. has_const = true;
  318. }
  319. int ref_index = return_type.find("&");
  320. if (ref_index != return_type.npos) {
  321. //return_type = return_type.substr(0,ref_index) + return_type.substr(ref_index+1);
  322. has_reference = true;
  323. }
  324. const CPPNetTypeMapper::TypeTranslator *tt = CPPNetTypeMapper::instance()->get_translator_from_cpp(return_type);
  325. TClass *return_type_class = gROOT->GetClass(tt->cpp_core_typename().c_str());
  326. if (return_type_class != 0) {
  327. is_abs_class = (return_type_class->Property() & kIsAbstract) != 0;
  328. }
  329. /// Given that, is this a getter or a setter? If the return is const, then this
  330. /// is a getter, no matter if it is a reference. Otherwise, a reference operator means
  331. /// it was a setter.
  332. bool is_setter = has_reference && !has_const && !is_abs_class;
  333. /// Now, lets log this puppy in. Error if return types are different!
  334. if (result_map.find(index_argument) == result_map.end()) {
  335. CPPIndexerInfo temp;
  336. temp._index_type = CPPNetTypeMapper::instance()->get_translator_from_cpp(method.arguments()[0].CPPTypeName());
  337. temp._return_type = tt;
  338. temp._method = &method;
  339. result_map[index_argument] = temp;
  340. } else {
  341. if (result_map[index_argument]._return_type->cpp_core_typename() != tt->cpp_core_typename()) {
  342. is_setter = false;
  343. ConverterErrorLog::log_type_error(method.ClassOfMethodDefinition(), "Indexer with argument '" + index_argument + "' has more than one return type ('"
  344. + return_type + "', '" + result_map[index_argument]._return_type->cpp_typename() + "')");
  345. }
  346. }
  347. if (is_setter) {
  348. result_map[index_argument]._is_setter = true;
  349. }
  350. }
  351. /// Turn it into a vector to return
  352. vector<CPPIndexerInfo> result = for_each(result_map.begin(), result_map.end(),
  353. copy_map_target_t<CPPIndexerInfo>()).as_vector();
  354. return result;
  355. }
  356. ///
  357. /// Returns a list of deep non-inherrited classes.
  358. ///
  359. set<string> GetNonInherritedClasses(const RootClassInfo &info)
  360. {
  361. auto &superClasses (info.GetDirectInheritedClasses());
  362. auto directSuper (info.GetBestClassToInherrit());
  363. set<string> inh_classes;
  364. for_each(superClasses.begin(), superClasses.end(), [&] (const string &cname)
  365. {
  366. if (directSuper != cname) {
  367. auto &classInfo (RootClassInfoCollection::GetRootClassInfo(cname));
  368. auto &deepClasses (classInfo.GetInheritedClassesDeep());
  369. copy(deepClasses.begin(), deepClasses.end(), inserter(inh_classes, inh_classes.begin()));
  370. inh_classes.insert(cname);
  371. }
  372. });
  373. inh_classes.insert(info.CPPName());
  374. return inh_classes;
  375. }
  376. // See if this property should be emitted in the class that is being worked on. The
  377. // list of classes that aren't in the direct inherritance path is passed to figure this out.
  378. bool propertyShouldBeEmitted (const RootClassProperty &prop, const set<string> &nonInheritedClasses)
  379. {
  380. bool getter_good = prop.isGetter() && nonInheritedClasses.find(prop.getter_method()->ClassOfMethodDefinition()) != nonInheritedClasses.end();
  381. bool setter_good = prop.isSetter() && nonInheritedClasses.find(prop.setter_method()->ClassOfMethodDefinition()) != nonInheritedClasses.end();
  382. return getter_good || setter_good;
  383. }
  384. }
  385. class emit_enum_as_static {
  386. public:
  387. inline emit_enum_as_static (SourceEmitter &emitter)
  388. : _emitter(emitter)
  389. {}
  390. inline void operator() (const pair<string, unsigned int> &item)
  391. {
  392. _emitter.start_line() << "static const unsigned int " << item.first << " = " << item.second << ";" << endl;
  393. }
  394. private:
  395. SourceEmitter &_emitter;
  396. };
  397. ///
  398. /// Helper functiont to write out static enum defs
  399. ///
  400. void write_header_enum_standard (const RootEnum &einfo, SourceEmitter &emitter, bool is_global = false)
  401. {
  402. if (is_global) {
  403. emitter.start_line() << "public ";
  404. } else {
  405. emitter.start_line();
  406. }
  407. emitter() << "enum class ";
  408. if (einfo.NameUnqualified() == "") {
  409. emitter() << "EClassConstants";
  410. } else {
  411. emitter() << einfo.NameUnqualified();
  412. }
  413. emitter() << endl;
  414. emitter.brace_open();
  415. for (int en = 0; en < einfo.values().size(); en++) {
  416. emitter.start_line() << einfo.values()[en].first << " = " << einfo.values()[en].second;
  417. if (en != einfo.values().size()-1) {
  418. emitter() << ",";
  419. }
  420. emitter() << endl;
  421. }
  422. emitter.brace_close(true);
  423. }
  424. ///
  425. /// Write the enum specs
  426. ///
  427. void write_header_enums (RootClassInfo &class_info, SourceEmitter &emitter, bool all_standard_format)
  428. {
  429. const vector<RootEnum> &class_enums (class_info.GetClassEnums());
  430. for (unsigned int i = 0; i < class_enums.size(); i++) {
  431. /// If they are not a named enum, then simulate them with a set of constants
  432. if (class_enums[i].NameUnqualified() == "" && !all_standard_format) {
  433. std::for_each (class_enums[i].values().begin(), class_enums[i].values().end(),
  434. emit_enum_as_static (emitter));
  435. } else {
  436. write_header_enum_standard (class_enums[i], emitter);
  437. }
  438. }
  439. }
  440. ///
  441. /// Generate the interface specification
  442. ///
  443. void ClassTranslator::generate_interface (RootClassInfo &class_info, SourceEmitter &emitter)
  444. {
  445. emitter.start_namespace("Interface");
  446. ///
  447. /// Add forward references for the interfaces
  448. ///
  449. for (unsigned int i = 0; i < class_info.GetReferencedClasses().size(); i++) {
  450. string referenced_classname = class_info.GetReferencedClasses()[i];
  451. if (CPPNetTypeMapper::instance()->has_mapping(referenced_classname)) {
  452. emitter.forward_interface_reference(RootClassInfoCollection::GetRootClassInfo(referenced_classname).NETName());
  453. }
  454. }
  455. ///
  456. /// And now the interface itself.
  457. ///
  458. auto class_features = FeatureManager::GetFeaturesFor(class_info);
  459. emitter.start_line() << "public interface class " << class_info.NETName() << endl;
  460. ///
  461. /// The interface can inherrit from a number of places...
  462. ///
  463. const vector<string> &inherited_classes (class_info.GetDirectInheritedClasses());
  464. set<string> inherited_interfaces;
  465. transform (inherited_classes.begin(), inherited_classes.end(),
  466. inserter(inherited_interfaces, inherited_interfaces.begin()),
  467. [] (const string &s) { return "ROOTNET::Interface::" + RootClassInfoCollection::GetRootClassInfo(s).NETName(); });
  468. auto others = class_features.get_additional_interfaces(class_info);
  469. copy (others.begin(), others.end(), inserter(inherited_interfaces, inherited_interfaces.begin()));
  470. if (inherited_interfaces.size() > 0) {
  471. emitter.start_line() << " : ";
  472. bool one = false;
  473. for_each (inherited_interfaces.begin(), inherited_interfaces.end(),
  474. [&emitter, &one] (const string &s) {
  475. if (one)
  476. emitter() << ", ";
  477. one = true;
  478. emitter() << s;
  479. });
  480. emitter() << endl;
  481. }
  482. emitter.brace_open();
  483. ///
  484. /// The special prototype for accessing the raw objects...
  485. ///
  486. emitter.start_line() << "::" << class_info.CPPName() << " *CPP_Instance_" << class_info.CPPName() << "(void);" << endl;
  487. ///
  488. /// Special prototype to set-to-null the instance object when ROOT (or similar) makes it go away, or to
  489. /// delete it.
  490. ///
  491. emitter.start_line() << "void SetNull (void);" << endl;
  492. emitter.start_line() << "void DeleteHeldObject (void);" << endl;
  493. emitter.start_line() << "void DropObjectFromTables (void);" << endl;
  494. emitter.start_line() << "int GetRawCPPPointer(void);" << endl;
  495. ///
  496. /// Put in all class defined enums now. They have to go early b/c they have to be declared
  497. /// when they are defined.
  498. ///
  499. write_header_enums (class_info, emitter, true);
  500. ///
  501. /// List all the prototypes for the class.
  502. /// TODO: This comes back clean, and needs to be fixed so that the fact we couldn't do a bunch of
  503. /// prototypes was because they weren't translatable needs to get recoreded! :-)
  504. ///
  505. set<string> already_done_headers;
  506. vector<RootClassMethod> indexerOperators;
  507. auto inh_classes(GetNonInherritedClasses(class_info));
  508. const vector<RootClassMethod> class_protos (class_info.GetAllPrototypesForThisClass(true));
  509. for (unsigned int i = 0; i < class_protos.size(); i++) {
  510. const RootClassMethod &method = class_protos[i];
  511. // Make sure what we are looking at should be in here!
  512. if (inh_classes.find(method.ClassOfMethodDefinition()) == inh_classes.end())
  513. continue;
  514. /// If it is an indexer, keep it for later
  515. if (method.IsIndexer()) {
  516. indexerOperators.push_back(method);
  517. }
  518. if (!method.IsGoodForInterface()) {
  519. continue;
  520. }
  521. /// Generate and write out the header.
  522. try {
  523. if (!method.has_return_value() || !method.get_return_type_translator()->is_reference_to_object()) {
  524. string n_header (method.generate_normalized_method_header());
  525. if (already_done_headers.find(n_header) == already_done_headers.end()) {
  526. already_done_headers.insert(n_header);
  527. if (method.IsStatic()) {
  528. emitter.start_line() << "static ";
  529. }
  530. emitter.start_line() << method.generate_method_header() << ";" << endl;
  531. }
  532. }
  533. } catch (runtime_error &e)
  534. {
  535. cout << " interface translation failed (" << method.CPPName() << "): " << e.what() << endl;
  536. }
  537. }
  538. ///
  539. /// Do the properties for this object.
  540. ///
  541. const vector<RootClassProperty> &properties (class_info.GetProperties());
  542. for (vector<RootClassProperty>::const_iterator itr = properties.begin(); itr != properties.end(); itr++) {
  543. // Make sure at least one of these guys is defined in this thing
  544. if (!propertyShouldBeEmitted(*itr, inh_classes))
  545. continue;
  546. emitter.start_line();
  547. if (itr->isStatic())
  548. emitter() << "static ";
  549. emitter() << "property " << itr->property_type() << " " << itr->name() << " {" << endl;
  550. if (itr->isGetter()) {
  551. emitter.start_line() << " " << itr->property_type() << " get ();" << endl;
  552. }
  553. if (itr->isSetter()) {
  554. emitter.start_line() << " void set (" << itr->property_type() << " value);" << endl;
  555. }
  556. emitter.start_line() << "}" << endl;
  557. }
  558. ///
  559. /// Do the fields for this object
  560. ///
  561. auto &fields (class_info.GetAllDataFields(true));
  562. for (int i = 0; i < fields.size(); i++) {
  563. const RootClassField &f(fields[i]);
  564. emitter.start_line() << "property " << f.NETType() << " " << f.NETName() << " {" << endl;
  565. if (f.GetterOK()) {
  566. emitter.start_line() << " " << f.NETType() << " get ();" << endl;
  567. }
  568. if (f.SetterOK()) {
  569. emitter.start_line() << " void set (" << f.NETType() << " value);" << endl;
  570. }
  571. emitter.start_line() << "}" << endl;
  572. }
  573. ///
  574. /// Put in a reference to the indexers so others can do the array lookups. :-)
  575. ///
  576. vector<CPPIndexerInfo> indexers (SortIndexers(indexerOperators));
  577. for (unsigned int i = 0; i < indexers.size(); i++) {
  578. CPPIndexerInfo &info (indexers[i]);
  579. if (inh_classes.find(info._method->ClassOfMethodDefinition()) == inh_classes.end())
  580. continue;
  581. emitter.start_line() << "property " << info._return_type->net_return_type_name() << " default[" << info._index_type->net_interface_name() << "] {" << endl;
  582. emitter.start_line() << " " << info._return_type->net_return_type_name() << " get (" << info._index_type->net_interface_name() << " index);" << endl;
  583. if (info._is_setter) {
  584. emitter.start_line() << " void set (" << info._index_type->net_interface_name() << " index, " << info._return_type->net_return_type_name() << " value);" << endl;
  585. }
  586. emitter.start_line() << "}" << endl;
  587. }
  588. ///
  589. /// Great. Now we can close it out
  590. ///
  591. emitter.brace_close(true); // End of class definition
  592. emitter.brace_close(); // End of namespace
  593. }
  594. ///
  595. /// Generate the interface static methods.
  596. ///
  597. void ClassTranslator::generate_interface_static_methods (RootClassInfo &class_info, SourceEmitter &emitter)
  598. {
  599. emitter.start_namespace("Interface");
  600. ///
  601. /// Work only on static methods here...
  602. ///
  603. auto inh_classes(GetNonInherritedClasses(class_info));
  604. set<string> already_done_headers;
  605. const vector<RootClassMethod> &protos (class_info.GetAllPrototypesForThisClass(true));
  606. for (unsigned int i = 0; i < protos.size(); i++) {
  607. const RootClassMethod &method = protos[i];
  608. if (!method.IsStatic() || !method.IsGoodForInterface()) {
  609. continue;
  610. }
  611. if (inh_classes.find(method.ClassOfMethodDefinition()) == inh_classes.end())
  612. continue;
  613. /// Generate and write out the header.
  614. try {
  615. string n_header (method.generate_normalized_method_header());
  616. if (already_done_headers.find(n_header) == already_done_headers.end()) {
  617. already_done_headers.insert(n_header);
  618. emitter.start_line() << method.generate_method_header(true) << "" << endl;
  619. } else {
  620. continue;
  621. }
  622. } catch (runtime_error &e)
  623. {
  624. cout << " interface translation failed (" << method.CPPName() << "): " << e.what() << endl;
  625. }
  626. ///
  627. /// Generate a call to the static method of the actual object!
  628. ///
  629. emitter.brace_open();
  630. emitter.start_line();
  631. if (method.has_return_value()) {
  632. emitter() << "return ";
  633. }
  634. emitter() << "ROOTNET::" << class_info.NETName() << "::" << method.NETName() << "(";
  635. for (unsigned int i = 0; i < method.arguments().size(); i++) {
  636. if (i > 0) {
  637. emitter() << ", ";
  638. }
  639. emitter() << method.arguments()[i].get_argname();
  640. }
  641. emitter() << ");" << endl;
  642. emitter.brace_close();
  643. }
  644. ///
  645. /// Next, do the properties for the interface that have been declared static.
  646. ///
  647. const vector<RootClassProperty> &properties (class_info.GetProperties());
  648. for (vector<RootClassProperty>::const_iterator itr = properties.begin(); itr != properties.end(); itr++) {
  649. if (!itr->isStatic())
  650. continue;
  651. // Make sure at least one of these guys is defined in this thing
  652. if (!propertyShouldBeEmitted(*itr, inh_classes))
  653. continue;
  654. if (itr->isGetter()) {
  655. emitter.start_line() << itr->property_type() << " " << class_info.NETName() << "::" << itr->name() << "::get ()" << endl;
  656. emitter.brace_open();
  657. emit_function_body(*(itr->getter_method()), class_info, emitter);
  658. emitter.brace_close();
  659. }
  660. if (itr->isSetter()) {
  661. emitter.start_line() << "void " << class_info.NETName() << "::" << itr->name() << "::set (" << itr->property_type()
  662. << " " << itr->setter_method()->arguments()[0].get_argname() << ")" << endl;
  663. emitter.brace_open();
  664. emit_function_body(*(itr->setter_method()), class_info, emitter);
  665. emitter.brace_close();
  666. }
  667. }
  668. ///
  669. /// Great. Now we can close it out
  670. ///
  671. emitter.brace_close(); // End of namespace
  672. }
  673. namespace {
  674. // Emit the method headers for an operator. This is different than the classic one because
  675. // it is static - so we have to have both guys as operators.
  676. // We reverse the order so that as long as their is one
  677. vector<string> generate_operator_header (const RootClassMethod &method, bool emit_class_method_name = false)
  678. {
  679. auto mainObj = CPPNetTypeMapper::instance()->get_translator_from_cpp(method.OwnerClass().CPPName());
  680. auto base_arg (mainObj->net_typename() + " base_obj_a1");
  681. string args (method.generate_normalized_method_arguments(true));
  682. string args_sep = ", ";
  683. if (args.length() == 0)
  684. args_sep = "";
  685. //
  686. // We reverse the arguments so that you can something like "5 * obj" and "obj * 5".
  687. // However, if it is "obj * obj" and both obj's are same, then we can't do this because
  688. // we'll end up with ambigous operators.
  689. //
  690. int max_count = 2;
  691. const RootClassInfo &cInfo (method.OwnerClass());
  692. if (method.arguments().size() == 0)
  693. max_count = 1;
  694. if (method.arguments().size() > 0 && method.arguments()[0].RawCPPTypeName() == cInfo.CPPName())
  695. max_count = 1;
  696. //
  697. // Emit everything
  698. //
  699. vector<string> result;
  700. for (int count = 0; count < max_count; count++) {
  701. ostringstream header;
  702. if (method.has_return_value()) {
  703. header << method.get_return_type_translator()->net_typename() << " ";
  704. } else {
  705. header << "void ";
  706. }
  707. if (emit_class_method_name) {
  708. header << method.OwnerClass().NETName() << "::";
  709. }
  710. header << method.NETName()
  711. << "(";
  712. if (count == 0) {
  713. header << base_arg << args_sep << args;
  714. } else {
  715. header << args << args_sep << base_arg;
  716. }
  717. header << ")";
  718. result.push_back(header.str());
  719. }
  720. return result;
  721. }
  722. }
  723. ///
  724. /// Generate the header for the class.
  725. ///
  726. void ClassTranslator::generate_class_header (RootClassInfo &info, SourceEmitter &emitter)
  727. {
  728. ///
  729. /// Emit the class declaration, along with the inherritance path.
  730. ///
  731. emitter.start_line() << "public ref class " << info.NETName() << endl;
  732. auto bestClassToInherrit (info.GetBestClassToInherrit());
  733. if (bestClassToInherrit.size() == 0) {
  734. emitter.start_line() << " : ROOTNET::Utility::ROOTDOTNETBaseTObject," << endl;
  735. } else {
  736. auto &infoInherrit (RootClassInfoCollection::GetRootClassInfo(bestClassToInherrit));
  737. emitter.start_line() << " : ROOTNET::" << infoInherrit.NETName() << "," << endl;
  738. }
  739. emitter.start_line() << " ROOTNET::Interface::" << info.NETName() << endl;
  740. emitter.brace_open();
  741. //
  742. // Do protected
  743. //
  744. emitter.start_line() << "protected:" << endl;
  745. emitter.start_line() << " void SetInstance (::" << info.CPPName() << "* instance) {" << endl;
  746. emitter.start_line() << " _instance = instance;" << endl;
  747. if (bestClassToInherrit.size() != 0)
  748. emitter.start_line() << " N" << bestClassToInherrit << "::SetInstance (instance);" << endl;
  749. emitter.start_line() << "}" << endl;
  750. ///
  751. /// Hold onto the C++ pointer!
  752. ///
  753. emitter.start_line() << "private:" << endl;
  754. emitter.start_line() << "::" << info.CPPName() << " *_instance;" << endl;
  755. emitter() << endl;
  756. ///
  757. /// Give us some access to the C++ pointers for all inherited classes...
  758. /// When dealing with inherritance make sure that we do the CPP_Instance's
  759. /// correctly.
  760. ///
  761. auto inh_classes(GetNonInherritedClasses(info));
  762. for_each(inh_classes.begin(), inh_classes.end(), [&] (const string &cls)
  763. {
  764. if (cls.find("<") == cls.npos) {
  765. emitter.start_line() << "public:" << endl;
  766. emitter.start_line() << "virtual ::" << cls << " *CPP_Instance_" << cls << "(void)" << endl;
  767. emitter.brace_open();
  768. emitter.start_line() << " return _instance;" << endl;
  769. emitter.brace_close();
  770. }
  771. });
  772. ///
  773. /// And a ctor that can start from a pointer
  774. ///
  775. emitter.start_line() << info.NETName() << "(::" << info.CPPName() << " *instance);" << endl;
  776. emitter.start_line() << info.NETName() << "(::" << info.CPPName() << " &instance);" << endl;
  777. //
  778. // Common method to get out the TObject and void pointer.
  779. //
  780. emitter.start_line() << "protected:" << endl;
  781. if (info.InheritsFromTObject() || info.CPPName() == "TObject") {
  782. emitter.start_line() << "virtual ::TObject *GetTObjectPointer (void) override { return _instance; }" << endl;
  783. emitter.start_line() << "virtual ::TClass *GetAssociatedTClassInfo (void) override" << endl;
  784. emitter.brace_open();
  785. emitter.start_line() << "if (_instance == nullptr)" << endl;
  786. emitter.start_line() << " return nullptr;" << endl;
  787. emitter.start_line() << "return _instance->IsA();" << endl;
  788. emitter.brace_close();
  789. } else {
  790. emitter.start_line() << "virtual ::TObject *GetTObjectPointer (void) override { return (::TObject*) 0; }" << endl;
  791. emitter.start_line() << "virtual ::TClass *GetAssociatedTClassInfo (void) override" << endl;
  792. emitter.brace_open();
  793. emitter.start_line() << "return TClass::GetClass(\"" << info.CPPName() << "\");" << endl;
  794. emitter.brace_close();
  795. }
  796. emitter.start_line() << "virtual void *GetVoidPointer (void) override { return _instance; }" << endl;
  797. ///
  798. /// And a guy to set the thing to null
  799. ///
  800. emitter.start_line() << "public:" << endl;
  801. emitter.start_line() << "virtual void SetNull (void) override { _instance = 0; SetNullReason(ROOTNET::Utility::ReasonPointerNullEnum::kSetNullCalled);}" << endl;
  802. emitter.start_line() << "virtual void DropObjectFromTables (void) override;" << endl;
  803. ///
  804. /// Allow for deleting, as long as we can get at the dtor!
  805. ///
  806. if (info.CanDelete()) {
  807. emitter.start_line() << "virtual void DeleteHeldObject (void) override { delete _instance; _instance = 0;SetNullReason(ROOTNET::Utility::ReasonPointerNullEnum::kObjectDeleted);}" << endl;
  808. } else {
  809. emitter.start_line() << "virtual void DeleteHeldObject (void) override {_instance = 0;SetNullReason(ROOTNET::Utility::ReasonPointerNullEnum::kObjectNotDeleted);}" << endl;
  810. }
  811. ///
  812. /// Allow one to get a hold of the raw ponter. Yes, this is evil. But sometimes it is necessary.
  813. /// This will break if built in x64 I would guess. :-(
  814. ///
  815. emitter.start_line() << "virtual int GetRawCPPPointer(void)";
  816. if (bestClassToInherrit.size() > 0)
  817. emitter() << " new";
  818. emitter() << " {return (int) _instance;}" << endl;
  819. ///
  820. /// Emit all the method signatures...
  821. ///
  822. set<string> written_methods;
  823. vector<RootClassMethod> arrayOperators;
  824. vector<RootClassMethod> mathOperators;
  825. const vector<RootClassMethod> &class_protos(info.GetAllPrototypesForThisClass(true));
  826. for (unsigned int i = 0; i < class_protos.size(); i++) {
  827. const RootClassMethod &method = class_protos[i];
  828. //
  829. // We only want to implement this class if it is in one of the classes we have implemented as an
  830. // interface.
  831. //
  832. if (inh_classes.find(method.ClassOfMethodDefinition()) == inh_classes.end())
  833. continue;
  834. //
  835. // Accumulate the various indexers, or if there is a problem with this method, etc.
  836. //
  837. if (method.IsIndexer()) {
  838. arrayOperators.push_back(method);
  839. continue;
  840. }
  841. if (!method.IsGoodForClass()) {
  842. continue;
  843. }
  844. if (method.IsMathOperator())
  845. {
  846. mathOperators.push_back(method);
  847. continue;
  848. }
  849. try {
  850. if (method.IsCtor()) {
  851. string n_header = method.generate_normalized_method_header();
  852. if (written_methods.find(n_header) != written_methods.end()) {
  853. continue;
  854. }
  855. written_methods.insert(n_header);
  856. emitter.start_line() << method.generate_method_header() << ";" << endl;
  857. } else {
  858. /// We don't deal with references in returns yet...
  859. if (!method.has_return_value() || !method.get_return_type_translator()->is_reference_to_object()) {
  860. string n_header = method.generate_normalized_method_header();
  861. if (written_methods.find(n_header) != written_methods.end()) {
  862. ConverterErrorLog::log_type_error(method.return_type(), "Don't do references as returns from methods yet");
  863. continue;
  864. }
  865. written_methods.insert(n_header);
  866. ///
  867. /// The header should have everything in it, and since it is implementing something in
  868. /// the interface, we had better mark it virtual. Unless it is static, in which case it only
  869. /// exists here.
  870. ///
  871. emitter.start_line();
  872. if (method.IsStatic()) {
  873. emitter() << "static ";
  874. } else {
  875. emitter() << "virtual ";
  876. }
  877. emitter() << method.generate_method_header();
  878. if (method.IsDefaultOverride())
  879. emitter() << " override";
  880. emitter() << ";" << endl;
  881. }
  882. }
  883. } catch (runtime_error &e) {
  884. cout << " translation failed (" << method.CPPName() << "): " << e.what() << endl;
  885. continue;
  886. }
  887. }
  888. //
  889. // Do the math operators. Here we need to generate static versions so C# knows what to do.
  890. //
  891. emitter.start_line() << "// Math Operators for C#-like languages" << endl;
  892. for (vector<RootClassMethod>::const_iterator itr = mathOperators.begin(); itr != mathOperators.end(); itr++) {
  893. auto headers (generate_operator_header (*itr));
  894. for (vector<string>::const_iterator itr_h = headers.begin(); itr_h != headers.end(); itr_h++) {
  895. emitter.start_line() << "static ";
  896. emitter() << *itr_h << ";" << endl;
  897. }
  898. }
  899. ///
  900. /// Do the properties for this object.
  901. ///
  902. const vector<RootClassProperty> &properties (info.GetProperties());
  903. for (vector<RootClassProperty>::const_iterator itr = properties.begin(); itr != properties.end(); itr++) {
  904. // Make sure at least one of these guys is defined in this thing
  905. if (!propertyShouldBeEmitted(*itr, inh_classes))
  906. continue;
  907. // Emit the proper getters and setters
  908. emitter.start_line();
  909. if (itr->isStatic())
  910. emitter() << "static ";
  911. emitter() << "property " << itr->property_type() << " " << itr->name() << " {" << endl;
  912. if (itr->isGetter()) {
  913. emitter.start_line() << " ";
  914. if (!itr->isStatic())
  915. emitter() << "virtual ";
  916. emitter() << itr->property_type() << " get ()";
  917. if (itr->getter_method()->IsDefaultOverride())
  918. emitter() << " new";
  919. emitter() << ";" << endl;
  920. }
  921. if (itr->isSetter()) {
  922. emitter.start_line() << " ";
  923. if (!itr->isStatic())
  924. emitter() << "virtual ";
  925. emitter() << "void set (" << itr->property_type() << " value)";
  926. if (itr->setter_method()->IsDefaultOverride())
  927. emitter() << " new";
  928. emitter() << ";" << endl;
  929. }
  930. emitter.start_line() << "}" << endl;
  931. }
  932. ///
  933. /// Do the fields for this object
  934. ///
  935. auto &fields (info.GetAllDataFields(true));
  936. for (int i = 0; i < fields.size(); i++) {
  937. const RootClassField &f(fields[i]);
  938. // Make sure this field is in the proper class!
  939. if (inh_classes.find(f.ClassOfFieldDefinition()) == inh_classes.end())
  940. continue;
  941. emitter.start_line() << "property " << f.NETType() << " " << f.NETName() << " {" << endl;
  942. if (f.GetterOK()) {
  943. emitter.start_line() << " virtual " << f.NETType() << " get ();" << endl;
  944. }
  945. if (f.SetterOK()) {
  946. emitter.start_line() << " virtual void set (" << f.NETType() << " value);" << endl;
  947. }
  948. emitter.start_line() << "}" << endl;
  949. }
  950. ///
  951. /// Next, put in a reference to the indexers so others can do the array lookups. :-)
  952. ///
  953. vector<CPPIndexerInfo> indexers (SortIndexers(arrayOperators));
  954. for (unsigned int i = 0; i < indexers.size(); i++) {
  955. CPPIndexerInfo &info (indexers[i]);
  956. if (inh_classes.find(info._method->ClassOfMethodDefinition()) == inh_classes.end())
  957. continue;
  958. emitter.start_line() << "property " << info._return_type->net_return_type_name() << " default[" << info._index_type->net_interface_name() << "] {" << endl;
  959. emitter.start_line() << " virtual " << info._return_type->net_return_type_name() << " get (" << info._index_type->net_interface_name() << " index)";
  960. if (info._method->IsDefaultOverride())
  961. emitter() << " override";
  962. emitter() << ";" << endl;
  963. if (info._is_setter) {
  964. emitter.start_line() << " virtual void set (" << info._index_type->net_interface_name() << " index, " << info._return_type->net_return_type_name() << " value)";
  965. if (info._method->IsDefaultOverride())
  966. emitter() << " override";
  967. emitter() << ";" << endl;
  968. }
  969. emitter.start_line() << "}" << endl;
  970. }
  971. ///
  972. /// If there are any global variables, we need to emit those as well!
  973. /// There is something funny (and illegal) about calling the GetBsetObject from the static decl. Instead, we have to build a dummy
  974. /// routine first (or we get compiler errors).
  975. ///
  976. /// Make the accessor a property accessor so that we always call the Load. The reason for this is to make sure that we
  977. /// always get the latest version. For example, gDirectory is often switching and we will have to be able to deal with that
  978. /// here.
  979. ///
  980. /// We take a slightly different route for a non-TObject.
  981. ///
  982. if (type_has_globals(info.CPPName())) {
  983. auto &globals (list_of_globals_of_type(info.CPPName()));
  984. for (unsigned int i = 0; i < globals.size(); i++) {
  985. string loadCall;
  986. if (info.InheritsFromTObject()) {
  987. loadCall = "ROOTNET::Utility::ROOTObjectServices::GetBestObject<Interface::" + info.NETName() + "^>(::" + globals[i].Name() + ")";
  988. } else {
  989. loadCall = "gcnew " + info.NETName() + "(::" + globals[i].Name() + ")";
  990. }
  991. ///
  992. /// Now create the static property accessor
  993. ///
  994. string interfaceName = "Interface::" + info.NETName() + " ^";
  995. emitter.start_line() << "static property " << interfaceName << globals[i].Name() << endl;
  996. emitter.brace_open();
  997. emitter.start_line() << interfaceName << " get() { return " << loadCall << "; }" << endl;
  998. emitter.brace_close();
  999. }
  1000. }
  1001. ///
  1002. /// If there are any feature methods, now is the time!
  1003. ///
  1004. FeatureManager::GetFeaturesFor(info).emit_header_method_definitions(info, emitter);
  1005. ///
  1006. /// Done with the class decl!
  1007. ///
  1008. emitter.brace_close(true);
  1009. }
  1010. ///
  1011. /// Register this class with the monitor -- but only if it comes from TObject (because otherwise it isn't
  1012. /// plugged into any of the framework).
  1013. ///
  1014. void ClassTranslator::emit_registration (const RootClassInfo &info, SourceEmitter &emitter, bool we_own)
  1015. {
  1016. if (info.CPPName() == "TObject" || info.InheritsFromTObject()) {
  1017. emitter.start_line() << "ROOTNET::Utility::ROOTObjectManager::instance()->RegisterObject (_instance, this);" << endl;
  1018. if (we_own) {
  1019. emitter.start_line() << "_owner = true;" << endl;
  1020. } else {
  1021. emitter.start_line() << "_owner = false;" << endl;
  1022. }
  1023. }
  1024. }
  1025. namespace {
  1026. /// Translate a single type from .NET to CPP. Return the variable name
  1027. /// you should use in your code.
  1028. string emit_translation_net_cpp (const string &var_name, // Name in .net world
  1029. const CPPNetTypeMapper::TypeTranslator *trans, // the type pointer
  1030. SourceEmitter &emitter)
  1031. {
  1032. if (!trans->requires_translation_to_cpp()) {
  1033. return var_name;
  1034. }
  1035. string translated_argument ("trans_" + var_name);
  1036. trans->translate_to_cpp (var_name, translated_argument, emitter);
  1037. return translated_argument;
  1038. }
  1039. /// Emit the translators for each argument. Return a list of the argument names that can
  1040. /// be used to do the actual calls.
  1041. vector<string> emit_cpp_args (const vector<RootClassMethodArg> &args, SourceEmitter &emitter)
  1042. {
  1043. vector<string> cpp_argnames;
  1044. for (unsigned int i = 0; i < args.size(); i++) {
  1045. const CPPNetTypeMapper::TypeTranslator *trans = CPPNetTypeMapper::instance()->get_translator_from_cpp (args[i].CPPTypeName());
  1046. cpp_argnames.push_back(emit_translation_net_cpp(args[i].get_argname(), trans, emitter));
  1047. }
  1048. return cpp_argnames;
  1049. }
  1050. void emit_translation_net_cpp_cleanup (const string &arg_name, // Used in .NET world
  1051. const string &cpp_name, // Used in C++ world
  1052. const CPPNetTypeMapper::TypeTranslator *trans,
  1053. SourceEmitter &emitter)
  1054. {
  1055. if (trans->requires_cleanup_code()) {
  1056. trans->translate_to_cpp_cleanup (arg_name, cpp_name, emitter);
  1057. }
  1058. }
  1059. /// Issue the cleanup calls for argument names
  1060. void clean_up_args (const vector<RootClassMethodArg> &args,
  1061. const vector<string> &cpp_argnames,
  1062. SourceEmitter &emitter)
  1063. {
  1064. for (unsigned int i = 0; i < args.size(); i++) {
  1065. const CPPNetTypeMapper::TypeTranslator *trans = CPPNetTypeMapper::instance()->get_translator_from_cpp (args[i].CPPTypeName());
  1066. emit_translation_net_cpp_cleanup (args[i].get_argname(), cpp_argnames[i], trans, emitter);
  1067. }
  1068. }
  1069. string clean_up_net_name(const string &name)
  1070. {
  1071. string result = name;
  1072. for (int i = 0; i < result.size(); i++) {
  1073. if (result[i] == '-')
  1074. result[i] = '_';
  1075. if (result[i] == '>')
  1076. result[i] = '_';
  1077. }
  1078. return result;
  1079. }
  1080. /// Emit code to issue a "return" statement of some sort
  1081. void emit_return (const CPPNetTypeMapper::TypeTranslator *return_translator, const std::string &return_var, SourceEmitter &emitter, bool use_interface = false)
  1082. {
  1083. string return_var_name (return_var);
  1084. if (return_translator->requires_translation_to_net()) {
  1085. auto dotnet_return_var = clean_up_net_name ("dotnet_" + return_var);
  1086. return_translator->translate_to_net (dotnet_return_var, return_var, emitter, use_interface);
  1087. return_var_name = dotnet_return_var;
  1088. }
  1089. emitter.start_line() << "return " << return_var_name << ";" << endl;
  1090. }
  1091. }
  1092. ///
  1093. /// Write out the body of a function!
  1094. ///
  1095. void ClassTranslator::emit_function_body(const RootClassMethod &method, const RootClassInfo &info, SourceEmitter &emitter)
  1096. {
  1097. ///
  1098. /// If we can't translate the method, we should bail out right away.
  1099. ///
  1100. if (method.IsAmbiguous()) {
  1101. emitter.start_line() << "throw gcnew ::System::NotImplementedException(\"Method has ambiguous C++ resolution: not currently supported.\");" << endl;
  1102. return;
  1103. } else if (method.IsHidden()) {
  1104. emitter.start_line() << "throw gcnew ::System::NotImplementedException(\"Method has is protected in C++ class: can't be accessed.\");" << endl;
  1105. return;
  1106. }
  1107. ///
  1108. /// Setup for return - we may not use it (this function may not demand it).
  1109. ///
  1110. string return_var ("f_abz_result"); // Common (potential) name.
  1111. ///
  1112. /// Translate the arguments into CPP land from .net land
  1113. ///
  1114. const vector<RootClassMethodArg> &args = method.arguments();
  1115. vector<string> cpp_argnames (emit_cpp_args(args, emitter));
  1116. ///
  1117. /// Now that we have the arguments in hand, we can write the body of the function.
  1118. ///
  1119. if (method.IsCtor()) {
  1120. emitter.start_line() << "_instance = new ::" << info.CPPName() << "(";
  1121. for (unsigned int i = 0; i < cpp_argnames.size(); i++) {
  1122. if (i != 0) {
  1123. emitter() << ", ";
  1124. }
  1125. emitter() << cpp_argnames[i];
  1126. }
  1127. emitter() << ");" << endl;
  1128. // If this has a super-class, we need to set the instance there.
  1129. auto superInfo (info.GetBestClassToInherrit());
  1130. if (superInfo.size() != 0) {
  1131. auto &superInfoPtr = RootClassInfoCollection::GetRootClassInfo(superInfo);
  1132. emitter.start_line() << superInfoPtr.NETName() << "::SetInstance(_instance);" << endl;
  1133. }
  1134. emit_registration(info, emitter, true);
  1135. } else {
  1136. const CPPNetTypeMapper::TypeTranslator *return_translator = method.get_return_type_translator();
  1137. if (return_translator != 0) {
  1138. emitter.start_line() << return_translator->cpp_code_typename() << " " << return_var << " = ";
  1139. } else {
  1140. emitter.start_line();
  1141. }
  1142. /// If static, then make the static call
  1143. if (method.IsStatic()) {
  1144. emitter() << "::" << method.ClassOfMethodDefinition() << "::" << method.NETName();
  1145. } else {
  1146. if (method.IsConst()) {
  1147. emitter() << "((const " << info.CPPName() << " *) _instance)->";
  1148. } else {
  1149. emitter() << "_instance->";
  1150. }
  1151. emitter() << method.FullName();
  1152. }
  1153. emitter() << "(";
  1154. for (unsigned int i = 0; i < cpp_argnames.size(); i++) {
  1155. if (i != 0) {
  1156. emitter() << ", ";
  1157. }
  1158. emitter() << cpp_argnames[i];
  1159. }
  1160. emitter() << ");" << endl;
  1161. }
  1162. ///
  1163. /// Next, do any clean up required from the argument translation. I hope this is exception
  1164. /// safe!!! (memory leaks bad!!).
  1165. ///
  1166. clean_up_args (args, cpp_argnames, emitter);
  1167. ///
  1168. /// If there is a return.
  1169. ///
  1170. if ((!method.IsAmbiguous() && !method.IsHidden()) && !method.IsCtor() && method.has_return_value()) {
  1171. emit_return (method.get_return_type_translator(), return_var, emitter);
  1172. }
  1173. }
  1174. namespace {
  1175. // Get the operator out for a non-asignment operator ("operator+").
  1176. string parse_nonassign_operator (const RootClassMethod &method)
  1177. {
  1178. auto name = method.NETName().substr(string("operator").length());
  1179. return name;
  1180. }
  1181. }
  1182. ///
  1183. /// Generate the actual class.
  1184. ///
  1185. void ClassTranslator::generate_class_methods (RootClassInfo &info, SourceEmitter &emitter)
  1186. {
  1187. ///
  1188. /// Make sure that we are dealing with nullptr's that we can understand!
  1189. ///
  1190. emitter() << "#ifdef nullptr" << endl;
  1191. emitter() << "#undef nullptr" << endl;
  1192. emitter() << "#endif" << endl;
  1193. //
  1194. // If this isn't a base class then we will need to reference other guys in the c-tors.
  1195. //
  1196. auto superClass = info.GetBestClassToInherrit();
  1197. RootClassInfo *superClassInfo (nullptr);
  1198. if (superClass.size() != 0) {
  1199. superClassInfo = RootClassInfoCollection::GetRootClassInfoPtr(superClass);
  1200. }
  1201. ///
  1202. /// First, do our particular c-tors...
  1203. ///
  1204. emitter.start_line() << info.NETName() << "::" << info.NETName() << "(::" << info.CPPName() << " *instance)" << endl;
  1205. emitter.start_line() << " : _instance(instance)";
  1206. if (superClassInfo != nullptr) {
  1207. emitter() << ", " << superClassInfo->NETName() << "(_instance)";
  1208. }
  1209. emitter() << endl;
  1210. emitter.brace_open();
  1211. emit_registration(info, emitter, false);
  1212. emitter.brace_close();
  1213. emitter.start_line() << info.NETName() << "::" << info.NETName() << "(::" << info.CPPName() << " &instance)" << endl;
  1214. emitter.start_line() << " : _instance(&instance)";
  1215. if (superClassInfo != nullptr) {
  1216. emitter() << ", " << superClassInfo->NETName() << "(_instance)";
  1217. }
  1218. emitter() << endl;
  1219. emitter.brace_open();
  1220. em

Large files files are truncated, but you can click here to view the full file