/src/tools/wrappers-generator/name_converter.e

http://github.com/tybor/Liberty · Specman e · 297 lines · 203 code · 24 blank · 70 comment · 8 complexity · 9290cd4d821f192adf1bc5b1669d0dbd MD5 · raw file

  1. deferred class NAME_CONVERTER
  2. -- Query features to dcover if a symbol name does comply to SmartEiffel's
  3. -- naming rules and to convert arbitrary C symbols into valid Eiffel names
  4. -- of classes or features.
  5. insert
  6. PLATFORM
  7. EXCEPTIONS
  8. feature {ANY} -- Auxiliary features
  9. eiffel_feature (a_name: ABSTRACT_STRING): STRING
  10. -- Translate `a_name' content into a proper feature name for the
  11. -- Gnu-Eiffel language. "CamelCase" is translated into "camel_case",
  12. -- "ENOO" is translated into "enoo". Eventual underscores in front of
  13. -- `a_name' are removed: "__foo" becomes "foo"; symbols starting with
  14. -- underscores folloed by a number are prefixed with "a_"; reserved
  15. -- language names and names of features of class ANY are escaped.
  16. -- TODO: handle in a fairly
  17. require
  18. name_not_void: a_name /= Void
  19. name_not_empty: not a_name.is_empty
  20. do
  21. create Result.make_from_string(a_name)
  22. -- Remove header underscores.
  23. from
  24. until
  25. Result.first /= '_'
  26. loop
  27. Result.remove_first
  28. end
  29. -- If first character is a number prepend an `a_'
  30. if Result.first.is_digit then
  31. Result.prepend(once "a_")
  32. end
  33. insert_underscores(Result)
  34. -- Remove spurious underscores and the end
  35. from
  36. until
  37. Result.last /= '_'
  38. loop
  39. Result.remove_last
  40. end
  41. multiple_underscores_remover.substitute_all_in(Result)
  42. -- Deal with C++ names: turn lt<foo> into lt_of_foo
  43. -- TODO: queue<dock,deepspace::station> into queue_of_dock_and_deepspace_station
  44. lt_translator.substitute_all_in(Result)
  45. gt_translator.substitute_all_in(Result)
  46. namespace_separator_translator.substitute_all_in(Result)
  47. Result.to_lower
  48. Result := adapt(Result, once "_external")
  49. end
  50. eiffel_argument (a_name: ABSTRACT_STRING): STRING
  51. -- `a_name' content translated into a proper argument placeholder for
  52. -- the Gnu-Eiffel language. "CamelCase" is translated into
  53. -- "a_camel_case", "ENOO" is translated into "an_enoo". Eventual
  54. -- underscores in front of `a_name' are removed: "__foo" becomes
  55. -- "a_foo". See also `eiffel_feature'.
  56. require
  57. name_not_void: a_name /= Void
  58. local
  59. e_feature, e_prefix: ABSTRACT_STRING
  60. do
  61. e_feature := eiffel_feature(a_name)
  62. inspect
  63. e_feature.first
  64. when 'a', 'e', 'o', 'i', 'u' then
  65. e_prefix := once "an_"
  66. else
  67. e_prefix := once "a_"
  68. end
  69. Result := e_prefix + e_feature
  70. end
  71. insert_underscores (a_string: STRING)
  72. -- Insert an underscore ('_') before each uppercase letter following a lowercase one.
  73. require
  74. a_string /= Void
  75. not a_string.is_empty
  76. local
  77. i: INTEGER
  78. do
  79. from
  80. i := a_string.lower + 1
  81. until
  82. i > a_string.upper
  83. loop
  84. if a_string.item(i - 1).is_lower and a_string.item(i).is_upper then
  85. a_string.insert_character('_', i)
  86. i := i + 2
  87. else
  88. i := i + 1
  89. end
  90. end
  91. end
  92. camelcase_translator: REGULAR_EXPRESSION
  93. -- Insert an underscore ('_') between any lowercase letter followed by an uppercase one
  94. local
  95. builder: REGULAR_EXPRESSION_BUILDER
  96. once
  97. Result := builder.convert_perl_pattern("([a-z])([A-Z])")
  98. Result.prepare_substitution("\1_\2")
  99. end
  100. multiple_underscores_remover: REGULAR_EXPRESSION
  101. -- Replace all multiple occurences of underscore "_" with a single one
  102. local
  103. builder: REGULAR_EXPRESSION_BUILDER
  104. once
  105. Result := builder.convert_perl_pattern("(\_\_+)")
  106. Result.prepare_substitution("_")
  107. end
  108. lt_translator: REGULAR_EXPRESSION
  109. -- Replace all occurences of "<" (shown as "&lt;") with "_of_"
  110. local
  111. builder: REGULAR_EXPRESSION_BUILDER
  112. once
  113. Result := builder.convert_perl_pattern("(&lt;)")
  114. Result.prepare_substitution("_of_")
  115. end
  116. gt_translator: REGULAR_EXPRESSION
  117. -- Remove all occurences of ">" (shown as "&gt;")
  118. local
  119. builder: REGULAR_EXPRESSION_BUILDER
  120. once
  121. Result := builder.convert_perl_pattern("(&gt;)")
  122. Result.prepare_substitution("")
  123. end
  124. namespace_separator_translator: REGULAR_EXPRESSION
  125. -- Replace all occurences of "::" (C++ namespace separator) with "_"
  126. local
  127. builder: REGULAR_EXPRESSION_BUILDER
  128. once
  129. Result := builder.convert_perl_pattern("(&gt;)")
  130. Result.prepare_substitution("i")
  131. end
  132. is_public_name (a_name: ABSTRACT_STRING): BOOLEAN
  133. -- Does `a_name' start with an alphabetical character? Names
  134. -- starting with underscores or other strange characters are
  135. -- usually considered private in C/C++ languages.
  136. require
  137. not_void: a_name /= Void
  138. meaningful_length: a_name.count > 1
  139. do
  140. Result := a_name.first.is_letter
  141. end
  142. eiffel_class_name (a_string, a_suffix: ABSTRACT_STRING): STRING
  143. -- An Eiffel class name derived from `a_string'. Trailing and tail
  144. -- underscores are removed, dashes are turned into underscores,
  145. -- `a_suffix' is added at the end if not void, all is made uppercase.
  146. require
  147. a_string /= Void
  148. do
  149. create Result.make_from_string(a_string)
  150. -- Remove trailing underscores
  151. from
  152. until
  153. Result.first /= '_'
  154. loop
  155. Result.remove_first
  156. end
  157. check
  158. Result.last.code /= 0
  159. end
  160. -- Remove spurious underscores at the end
  161. from
  162. until
  163. Result.last /= '_'
  164. loop
  165. Result.remove_last
  166. end
  167. check
  168. Result.last.code /= 0
  169. end
  170. insert_underscores(Result)
  171. if a_suffix /= Void then
  172. Result.append(a_suffix)
  173. end
  174. check
  175. Result.last.code /= 0
  176. -- The reason of this check is not easy understandable here.
  177. -- It's actually a poor's man test of a strange, old bug of STRING
  178. -- shown by xml library that don't update capacity and actual
  179. -- length with an off-by-one length error
  180. end
  181. Result.replace_all('-', '_')
  182. Result.to_upper
  183. -- print("'"+Result+"' last charcter code is: "+Result.last.code.to_string+"%N")
  184. check
  185. Result.last.code /= 0
  186. end
  187. ensure
  188. Result /= Void
  189. is_valid_class_name(Result)
  190. end
  191. is_valid_class_name (a_name: ABSTRACT_STRING): BOOLEAN
  192. -- Does `a_name' represents a valid Eiffel class name? i.e. does it
  193. -- start with an upper-case letter and contain only upper-case
  194. -- letters, underscores and numbers?
  195. require
  196. a_name /= Void
  197. local
  198. iter: ITERATOR[CHARACTER]; c: CHARACTER
  199. do
  200. iter := a_name.new_iterator
  201. from
  202. iter.start
  203. Result := iter.item.is_upper
  204. iter.next
  205. until
  206. Result = False or else not iter.is_off
  207. loop
  208. c := iter.item
  209. Result := c.is_upper or else c.is_digit and c /= '.' or else c = '_'
  210. iter.next
  211. end
  212. end
  213. adapt (a_name, a_suffix: ABSTRACT_STRING): STRING
  214. -- A valid, adapted identifier for an Eiffel feature labelled
  215. -- `a_name'. Can be either `a_name' itself or a new string
  216. -- containing an adapatation. Reserved words and those of
  217. -- features belonging to ANY are "escaped", appending `a_suffix'.
  218. require
  219. name_not_void: a_name /= Void
  220. valid_name: a_name.first /= '_'
  221. suffix_not_void: a_suffix /= Void
  222. suffix_not_empty: not a_suffix.is_empty
  223. do
  224. if keywords.has(a_name) or else any_features.has(a_name) then
  225. Result := a_name + a_suffix
  226. elseif Result ?:= a_name then
  227. Result ::= a_name
  228. else
  229. create Result.make_from_string(a_name)
  230. end
  231. ensure
  232. Result /= Void
  233. end
  234. feature {} -- Constants
  235. keywords: HASHED_SET[ABSTRACT_STRING]
  236. once
  237. Result := {HASHED_SET[ABSTRACT_STRING] << "indexing"
  238. -- Keywords:
  239. -- related to classes
  240. , "class", "deferred", "expanded", "separate", "end", "obsolete", "inherit" -- related to inheritance
  241. , "insert", "creation", "feature", "rename", "redefine", "undefine", "select", "export", "require" -- design by contract
  242. , "ensure", "check", "debug", "invariant", "variant", "rescue", "local" -- features body
  243. , "do", "once", "alias", "external", "attribute", "if" -- control flow
  244. , "then", "else", "elseif", "when", "from", "until", "loop", "and" -- boolean operators
  245. , "or", "xor", "not", "implies" >> }
  246. end
  247. any_features: HASHED_SET[ABSTRACT_STRING]
  248. -- The names of the features contained in class ANY.
  249. -- The following "static" definition of the features of ANY
  250. -- somehow unacceptable in a perfect world. Yet computing it each
  251. -- and every time would enlarge the memory usage of the program
  252. -- quite a lot, not counting the runtime requirements. We will do
  253. -- it when we will cache compilation results.
  254. once
  255. -- The following "static" definition of the features of ANY
  256. -- somehow unacceptable in a perfect world. Yet computing it each
  257. -- and every time would enlarge the memory usage of the program
  258. -- quite a lot, not counting the runtime requirements. We will do
  259. -- it when we will cache compilation results.
  260. Result := {HASHED_SET[ABSTRACT_STRING] << "generating", "generator", "same_dynamic_type", "_equal", "standard__equal", "_deep_equal", "twin", "copy", "standard_twin", "standard_copy", "deep_twin", "default", "_default", "print_on", "tagged_out", "out", "out_in_tagged_out_memory", "tagged_out_memory", "fill_tagged_out_memory", "to_pointer", "_basic_expanded_type", "object_size" >> }
  261. end
  262. end -- class NAME_CONVERTER
  263. -- Copyright (C) 2008-2017: Paolo Redaelli
  264. -- wrappers-generator is free software: you can redistribute it and/or modify it
  265. -- under the terms of the GNU General Public License as publhed by the Free
  266. -- Software Foundation, either version 2 of the License, or (at your option)
  267. -- any later version.
  268. -- wrappers-generator is distributed in the hope that it will be useful, but
  269. -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  270. -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  271. -- more details.
  272. -- You should have received a copy of the GNU General Public License along with
  273. -- th program. If not, see <http://www.gnu.org/licenses/>.