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

http://github.com/tybor/Liberty · Specman e · 394 lines · 308 code · 41 blank · 45 comment · 18 complexity · 627ecdc04d822addd66b876fa80c57f0 MD5 · raw file

  1. class C_ENUM
  2. -- An "Enumeration" XML node in a file made by gccxml representing a C
  3. -- enum.
  4. -- TODO: Currently wrapper_type is "INTEGER"; this assumes two
  5. -- conditions:
  6. -- 1 - any enum value is actually an int;
  7. -- 2 - INTEGER has the same size of int
  8. -- As far as I know th condition shall apply on all architectures.
  9. inherit
  10. C_TYPE
  11. CONTEXTED_NODE
  12. IDENTIFIED_NODE
  13. FILED_NODE
  14. STORABLE_NODE
  15. TYPED_NODE
  16. WRAPPER_CLASS
  17. insert
  18. COLLECTION_SORTER[C_ENUM_VALUE]
  19. create {GCCXML_TREE}
  20. make
  21. feature {ANY}
  22. store
  23. do
  24. if is_named then
  25. symbols.put(Current, c_string_name)
  26. end
  27. types.put(Current, id)
  28. end
  29. has_wrapper: BOOLEAN True
  30. wrapper_type: STRING "INTEGER"
  31. is_fundamental: BOOLEAN False
  32. is_void: BOOLEAN False
  33. is_to_be_emitted: BOOLEAN
  34. local
  35. fn: STRING
  36. do
  37. fn := c_file.c_string_name
  38. Result := not emitted and then is_named and then file_exists(fn) and (global or else headers.has(fn)) and then not avoided_symbols.has(c_string_name)
  39. end
  40. emit_wrapper
  41. local
  42. filename: STRING; path: POSIX_PATH_NAME
  43. do
  44. if is_to_be_emitted then
  45. create path.make_from_string(directory)
  46. path.add_last(eiffel_name.as_lower + once ".e")
  47. filename := path.to_string
  48. log(once "Wrapping enum #(1) as #(2) on #(3)" # c_name.to_utf8 # eiffel_name # filename)
  49. create {TEXT_FILE_WRITE} output.connect_to(filename)
  50. emit_header
  51. emit_items
  52. emit_footer
  53. output.flush
  54. output.disconnect
  55. else
  56. log(once "Skipping enum `#(1)'.%N" # c_string_name)
  57. end
  58. emitted:=True
  59. end
  60. emit_header
  61. do
  62. buffer.reset_with(automatically_generated_header)
  63. buffer.append(expanded_class)
  64. buffer.append(eiffel_name)
  65. buffer.append_new_line
  66. emit_description_on(class_descriptions.reference_at(c_string_name), buffer)
  67. buffer.append(once "[
  68. -- Wrapper of enum #(1) defined in file #(2)
  69. ]" # c_string_name # c_file.c_string_name )
  70. buffer.append(once "%Ninsert ENUM%N%Ncreate {ANY} default_create%N")
  71. buffer.print_on(output)
  72. end
  73. emit_items
  74. do
  75. if children_count > 0 then
  76. if flag_enums.has(c_string_name) then
  77. log(once ", forcefully wrapped as flag.%N")
  78. append_flag_items
  79. elseif have_flags_values then
  80. log(once ", as flag.%N")
  81. append_flag_items
  82. else
  83. log(once ", as an enumeration.%N")
  84. append_enumeration_items
  85. end
  86. else
  87. log(once "... fieldless.%N")
  88. end
  89. output.put_line(once "feature {ANY} -- Validity")
  90. validity_query.print_on(output)
  91. output.put_line(once "feature {ANY} -- Setters")
  92. setters.print_on(output)
  93. output.put_line(once "feature {ANY} -- Queries")
  94. queries.print_on(output)
  95. output.put_line(once "feature {WRAPPER, WRAPPER_HANDLER} -- Low level values")
  96. low_level_values.print_on(output)
  97. end
  98. emit_footer
  99. do
  100. buffer.append("%Nend -- class #(1)%N" # eiffel_name)
  101. buffer.print_on(output)
  102. end
  103. suffix: STRING "_ENUM"
  104. have_flags_values: BOOLEAN
  105. -- Can the values of `an_enumeration' be used as flags? They can be
  106. -- used as flags when they are different powers of 2, i.e. setting
  107. -- each a different bit, and there is no zero value.
  108. require
  109. has_children: children_count > 0
  110. local
  111. i, flags_so_far, value: INTEGER; enum_value: C_ENUM_VALUE
  112. do
  113. from
  114. i := 1
  115. Result := True
  116. until
  117. Result = False or else i > children_count
  118. loop
  119. enum_value ?= child(i)
  120. if enum_value /= Void then
  121. value := enum_value.value.to_integer
  122. if value > 0 and then value.is_a_power_of_2 and flags_so_far & value = 0 then
  123. -- value is valid and indipendent from other values so far.
  124. flags_so_far := flags_so_far | value
  125. else
  126. Result := False
  127. end
  128. else
  129. log(once "Warning: enum at line #(1) has at least a value that is not an EnumValue!"#line.out)
  130. end
  131. i := i + 1
  132. end
  133. end
  134. feature {ANY} -- Emitting "normal" enumeration
  135. append_enumeration_items
  136. require
  137. has_children: values.count > 0
  138. local
  139. i: INTEGER
  140. do
  141. initialize_validity_query
  142. setters.reset_with(once "%Tdefault_create,%N")
  143. values.first.append_to_buffers
  144. if values.count > 1 then
  145. from
  146. i := values.lower + 1
  147. until
  148. i > values.upper
  149. loop
  150. append_separators
  151. values.item(i).append_to_buffers
  152. i := i + 1
  153. end
  154. end
  155. finalize_validity_query
  156. end
  157. initialize_validity_query
  158. do
  159. validity_query.reset_with(once " is_valid_value (a_value: INTEGER): BOOLEAN%N%
  160. % do%N%
  161. % Result := (")
  162. ensure
  163. validity_query_grew: validity_query.count > old validity_query.count
  164. end
  165. finalize_validity_query
  166. do
  167. validity_query.append(once ")%N%T%Tend%N%N")
  168. ensure
  169. validity_query_grew: validity_query.count > old validity_query.count
  170. end
  171. append_separators
  172. -- Append various separators to `validity_query', `queries' and
  173. -- `setters' buffers.
  174. do
  175. validity_query.append(once " or else%N%T%T%T%T")
  176. end
  177. feature {ANY} -- Emitting "flag" enumeration
  178. append_flag_items
  179. require
  180. has_children: values.count > 0
  181. local
  182. i: INTEGER
  183. do
  184. initialize_flag_validity_query
  185. setters.reset_with(once "%Tdefault_create,%N")
  186. values.first.append_as_flag_to_buffers
  187. if values.count > 1 then
  188. from
  189. i := values.lower + 1
  190. until
  191. i > values.upper
  192. loop
  193. append_flag_separators
  194. values.item(i).append_as_flag_to_buffers
  195. i := i + 1
  196. end
  197. end
  198. finalize_flag_validity_query
  199. end
  200. initialize_flag_validity_query
  201. do
  202. validity_query.reset_with(once " is_valid_value (a_value: INTEGER): BOOLEAN%N%
  203. % do%N%
  204. % Result := (a_value=0 or (a_value & (")
  205. ensure
  206. validity_query_grew: validity_query.count > old validity_query.count
  207. end
  208. finalize_flag_validity_query
  209. do
  210. validity_query.append(once ")).to_boolean)%N%T%Tend%N%N")
  211. ensure
  212. validity_query_grew: validity_query.count > old validity_query.count
  213. end
  214. append_flag_separators
  215. -- Append various separators to `validity_query', `queries' and
  216. -- `setters' buffers.
  217. do
  218. validity_query.append(once " | %N%T%T%T%T")
  219. end
  220. feature {C_ENUM_VALUE} -- Implementation
  221. shortest_length: INTEGER_32
  222. -- The length of the shortest enumeration value
  223. local
  224. i: INTEGER
  225. do
  226. from
  227. i := values.upper - 1
  228. Result := values.last.c_name.count
  229. until
  230. i < values.lower
  231. loop
  232. Result := Result.min(values.item(i).c_name.count)
  233. i := i - 1
  234. end
  235. end
  236. longest_prefix: INTEGER
  237. -- The length of longest prefix common to all values of Current enumeration
  238. -- Useful to remove the common prefix of many enumeration values.
  239. -- Zero (0) when an enumeration has only one element
  240. local
  241. i, upper: INTEGER
  242. do
  243. if values.count > 1 then
  244. if prefix_length.is_default then
  245. from
  246. prefix_length := values.first.c_name.lower
  247. upper := shortest_length
  248. until
  249. prefix_length >= upper or else not same_character_at_index(prefix_length)
  250. loop
  251. prefix_length := prefix_length + 1
  252. end
  253. prefix_length := prefix_length - 1
  254. -- Used during development of th feature. Dabled because it's too verbose
  255. debug
  256. if verbose then
  257. print(once "'")
  258. print(values.first.c_name.as_utf8.substring(1, prefix_length))
  259. print(once "'(")
  260. print(prefix_length.to_string)
  261. print(once " characters) longest common prefix of ")
  262. from
  263. i := values.lower
  264. until
  265. i > values.upper - 1
  266. loop
  267. print(values.item(i).c_name.out)
  268. print(once ", ")
  269. i := i + 1
  270. end
  271. print(values.last.c_string_name)
  272. print(once ".%N")
  273. end
  274. end
  275. Result := prefix_length
  276. else
  277. -- result has been already computed
  278. Result := prefix_length
  279. end
  280. else
  281. -- enumeration has only one value
  282. Result := 0
  283. end
  284. ensure
  285. shorter_than_shortest_item: Result < shortest_length -- otherwe the shortest item will get an empty label
  286. end
  287. values: FAST_ARRAY[C_ENUM_VALUE]
  288. -- The C_ENUM_VALUE children of Current C_ENUM
  289. local
  290. a_value: C_ENUM_VALUE; i: INTEGER
  291. do
  292. if hidden_values = Void then
  293. create hidden_values.with_capacity(children_count)
  294. from
  295. i := 1
  296. until
  297. i > children_count
  298. loop
  299. a_value ?= child(i)
  300. if a_value /= Void then
  301. hidden_values.add_last(a_value)
  302. end
  303. i := i + 1
  304. end
  305. -- Sort the result to get a stable order of the wrapped features.
  306. -- We may also have used an inherently sorted collection, but since
  307. -- the features collections we are sorting aren't usually bigger
  308. -- than a few dozens of items the overhead of a sorted collection
  309. -- couldn't be justified. Th last tense hasn't actually been
  310. -- tested.
  311. if hidden_values.count > 1 then
  312. sort(hidden_values)
  313. end
  314. end
  315. Result := hidden_values
  316. end
  317. feature {} -- Implementation
  318. hidden_values: like values
  319. prefix_length: like longest_prefix
  320. same_character_at_index (an_index: INTEGER): BOOLEAN
  321. -- Do all values have the same characters at `an_index' in their name?
  322. require
  323. has_values: values.count > 1
  324. an_index <= shortest_length
  325. local
  326. c: INTEGER_32; i: INTEGER
  327. do
  328. c := values.first.c_name.item(an_index)
  329. --print(" (sc@"+an_index.out+": ")
  330. from
  331. i := values.lower
  332. Result := True
  333. until
  334. not Result or else i > values.upper
  335. loop
  336. Result := values.item(i).c_name.item(an_index) = c
  337. --print(values.item(i).c_name.item(an_index).to_character.out+",")
  338. i := i + 1
  339. end
  340. --print(")="+Result.out+" ")
  341. end --invariant name.is_equal(once U"Enumeration")
  342. end -- class C_ENUM
  343. -- Copyright (C) 2008-2017: ,2009,2010 Paolo Redaelli
  344. -- wrappers-generator is free software: you can redistribute it and/or modify it
  345. -- under the terms of the GNU General Public License as publhed by the Free
  346. -- Software Foundation, either version 2 of the License, or (at your option)
  347. -- any later version.
  348. -- wrappers-generator is distributed in the hope that it will be useful, but
  349. -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  350. -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  351. -- more details.
  352. -- You should have received a copy of the GNU General Public License along with
  353. -- th program. If not, see <http://www.gnu.org/licenses/>.