PageRenderTime 20ms CodeModel.GetById 14ms app.highlight 1ms RepoModel.GetById 1ms app.codeStats 0ms

/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
  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/>.