python_export_utils.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /******************************************************************************
  2. *
  3. * Copyright (C) 2020 by
  4. * The Salk Institute for Biological Studies
  5. *
  6. * Use of this source code is governed by an MIT-style
  7. * license that can be found in the LICENSE file or at
  8. * https://opensource.org/licenses/MIT.
  9. *
  10. ******************************************************************************/
  11. #include <fstream>
  12. #include <regex>
  13. #include "api/python_export_utils.h"
  14. #include "api/python_export_constants.h"
  15. namespace MCell {
  16. namespace API {
  17. using namespace std;
  18. bool PythonExportContext::already_exported(const BaseDataClass* obj) const {
  19. return exported_objects.count(obj) != 0;
  20. }
  21. std::string PythonExportContext::get_exported_name(const BaseDataClass* obj) const {
  22. assert(already_exported(obj));
  23. return exported_objects.find(obj)->second;
  24. }
  25. void PythonExportContext::add_exported(const BaseDataClass* obj, const std::string& name) {
  26. assert(!already_exported(obj));
  27. exported_objects[obj] = name;
  28. }
  29. uint PythonExportContext::postinc_counter(const std::string& underscored_class_name) {
  30. uint res;
  31. auto it = counters.find(underscored_class_name);
  32. if (it != counters.end()) {
  33. res = it->second;
  34. it->second++;
  35. }
  36. else {
  37. res = 0;
  38. counters[underscored_class_name] = 1;
  39. }
  40. return res;
  41. }
  42. std::string fix_id(const std::string& str) {
  43. std::string res;
  44. for (char c: str) {
  45. if (c == '+') {
  46. res += "_plus_";
  47. }
  48. else if (c == '-') {
  49. res += "_minus_";
  50. }
  51. else if (c == '*') {
  52. res += "_mul_";
  53. }
  54. else if (c == '/') {
  55. res += "_div_";
  56. }
  57. else if (c == '?') {
  58. res += "_anybond_";
  59. }
  60. else if (c == '!') {
  61. res += "_bond_";
  62. }
  63. else if (c == '(') {
  64. res += "_ps_";
  65. }
  66. else if (c == ')') {
  67. res += "_pe_";
  68. }
  69. else if (
  70. c == ' ' || c == '.' || c == '_' ||
  71. c == ',' || c == '~') {
  72. res += "_";
  73. }
  74. else if (isalnum(c)) {
  75. res += c;
  76. }
  77. // ignoring the rest of the characters
  78. }
  79. return res;
  80. }
  81. string get_filename(const string& output_files_prefix, const string file_suffix, const char* ext) {
  82. if (output_files_prefix == "" || output_files_prefix.back() == '/' || output_files_prefix.back() == '\\') {
  83. return output_files_prefix + file_suffix + ext;
  84. }
  85. else {
  86. return output_files_prefix + "_" + file_suffix + ext;
  87. }
  88. }
  89. void open_and_check_file_w_prefix(
  90. const string& output_files_prefix, const string file_suffix, ofstream& out,
  91. const bool for_append, const bool bngl) {
  92. string file_name = get_filename(output_files_prefix, file_suffix, (bngl) ? BNGL_EXT : PY_EXT);
  93. if (for_append) {
  94. cout << "Appending to " + file_name + ".\n";
  95. out.open(file_name, ios::app);
  96. }
  97. else {
  98. cout << "Generating file " + file_name + ".\n";
  99. out.open(file_name);
  100. }
  101. out.precision(FLOAT_OUT_PRECISION);
  102. if (!out.is_open()) {
  103. throw ConversionError("Could not open file '" + file_name + "' for writing.");
  104. }
  105. }
  106. std::string get_description(const Json::Value& value) {
  107. if (value.isMember(KEY_DESCRIPTION)) {
  108. return value[KEY_DESCRIPTION].asString();
  109. }
  110. else {
  111. return "";
  112. }
  113. }
  114. void gen_description(std::ostream& out, const std::string desc, const std::string ind) {
  115. if (desc != "") {
  116. out << ind << "# " << desc << "\n";
  117. }
  118. }
  119. void gen_description(std::ostream& out, Json::Value& value, const std::string ind) {
  120. if (value.isMember(KEY_DESCRIPTION)) {
  121. string desc = value[KEY_DESCRIPTION].asString();
  122. if (desc != "") {
  123. out << ind << "# " << desc << "\n";
  124. }
  125. }
  126. }
  127. void gen_ctor_call(std::ostream& out, std::string name, std::string class_name, bool has_params) {
  128. if (name != "") {
  129. out << make_id(name) << " = " << MDOT << class_name;
  130. }
  131. else {
  132. out << MDOT << class_name;
  133. }
  134. if (has_params) {
  135. out << "(\n";
  136. }
  137. else {
  138. out << "()\n";
  139. }
  140. }
  141. // replaces '.' with '_' and does potentially other conversions
  142. std::string make_id(const std::string& s) {
  143. string res = s;
  144. // do not do changes if the ID starts with 'm.' -> constant from
  145. // the mcell module ID that cannot have dots that we need to replace in it anyway
  146. if (res.size() <= 2 || (res.size() > 2 && res.substr(0, strlen(MDOT)) != MDOT)) {
  147. res = fix_id(res);
  148. }
  149. return res;
  150. }
  151. string fix_param_id(const std::string& str) {
  152. assert(str.size() > 0);
  153. if (str[0] == '_') {
  154. // underscore denotes private variables in Python
  155. return "und" + str;
  156. }
  157. else {
  158. return str;
  159. }
  160. }
  161. void gen_param_expr(std::ostream& out, std::string name, const std::string& value, bool comma) {
  162. std::string python_expr;
  163. // replace operator ^ with operator ** and '_' at the beginning with 'und_'
  164. python_expr = fix_param_id(regex_replace(value, regex("\\^"), "**"));
  165. out << IND << name << " = " << python_expr << (comma?",":"") << "\n";
  166. }
  167. } // namespace API
  168. } // namespace MCell