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