PageRenderTime 15ms CodeModel.GetById 10ms app.highlight 2ms RepoModel.GetById 1ms app.codeStats 0ms

/src/tools/semantics/types/type_builder/liberty_type_parent_features_loader.e

http://github.com/tybor/Liberty
Specman e | 411 lines | 362 code | 18 blank | 31 comment | 18 complexity | 5fb9bb5578e97cd939e758d65bfa07ac MD5 | raw file
  1-- This file is part of Liberty Eiffel.
  2--
  3-- Liberty Eiffel is free software: you can redistribute it and/or modify
  4-- it under the terms of the GNU General Public License as published by
  5-- the Free Software Foundation, version 3 of the License.
  6--
  7-- Liberty Eiffel is distributed in the hope that it will be useful,
  8-- but WITHOUT ANY WARRANTY; without even the implied warranty of
  9-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 10-- GNU General Public License for more details.
 11--
 12-- You should have received a copy of the GNU General Public License
 13-- along with Liberty Eiffel.  If not, see <http://www.gnu.org/licenses/>.
 14--
 15class LIBERTY_TYPE_PARENT_FEATURES_LOADER
 16   --
 17   -- Loads the type's parents' features.
 18   --
 19   -- Also loads the parent invariant.
 20   --
 21
 22insert
 23   LIBERTY_TYPE_BUILDER_TOOLS
 24
 25creation {LIBERTY_TYPE_BUILDER}
 26   make
 27
 28feature {}
 29   make (a_builder: like builder; a_current_entity: like current_entity; a_universe: like universe; a_effective_generic_parameters: like effective_generic_parameters; a_redefined_features: like redefined_features) is
 30      require
 31         a_builder /= Void
 32         a_current_entity /= Void
 33         a_universe /= Void
 34         a_effective_generic_parameters /= Void
 35         a_redefined_features /= Void
 36      do
 37         builder := a_builder
 38         current_entity := a_current_entity
 39         type := a_current_entity.result_type
 40         universe := a_universe
 41         effective_generic_parameters := a_effective_generic_parameters
 42         create {HASHED_DICTIONARY[LIBERTY_FEATURE_DEFINITION, LIBERTY_FEATURE_NAME]} parent_features.with_capacity(50) -- ANY contains 50 features
 43         redefined_features := a_redefined_features
 44      ensure
 45         builder = a_builder
 46         current_entity = a_current_entity
 47         universe = a_universe
 48         effective_generic_parameters = a_effective_generic_parameters
 49         redefined_features = a_redefined_features
 50      end
 51
 52   universe: LIBERTY_UNIVERSE
 53
 54feature {LIBERTY_TYPE_BUILDER}
 55   load is
 56      local
 57         has_parents: BOOLEAN
 58      do
 59         has_parents := inject_parents(type.ast.inherit_clause, False)
 60         has_parents := inject_parents(type.ast.insert_clause, has_parents)
 61         if not has_parents and then not errors.has_error then
 62            inject_parent_invariant(universe.type_any)
 63            inject_parent_features(universe.type_any, Void)
 64         end
 65         push_parent_features_in_type
 66         if not redefined_features.is_empty then
 67            builder.set_redefined_features(redefined_features)
 68         end
 69      end
 70
 71feature {}
 72   inject_parents (parents: LIBERTY_AST_LIST[LIBERTY_AST_PARENT]; had_parents: BOOLEAN): BOOLEAN is
 73      local
 74         i: INTEGER; parent_clause: LIBERTY_AST_PARENT
 75         parent: LIBERTY_TYPE; actual_parent: LIBERTY_ACTUAL_TYPE
 76      do
 77         from
 78            Result := had_parents
 79            i := parents.list_lower
 80         until
 81            errors.has_error or else i > parents.list_upper
 82         loop
 83            parent_clause := parents.list_item(i)
 84            parent := type_lookup.resolver.type(parent_clause.type_definition)
 85            if parent = Void then
 86               --|*** TODO: error, parent not found
 87               not_yet_implemented
 88            end
 89            actual_parent ::= parent.known_type
 90            check
 91               type.is_child_of(actual_parent)
 92            end
 93            inject_parent_invariant(actual_parent)
 94            inject_parent_features(actual_parent, parent_clause.parent_clause)
 95            Result := True
 96            i := i + 1
 97         end
 98      end
 99
100   inject_parent_invariant (parent: LIBERTY_ACTUAL_TYPE) is
101      do
102         --|*** TODO
103      end
104
105   inject_parent_features (parent: LIBERTY_ACTUAL_TYPE; clause: LIBERTY_AST_PARENT_CLAUSE) is
106      local
107         i: INTEGER; fd, parent_fd, actual_fd: LIBERTY_FEATURE_DEFINITION; feature_name: LIBERTY_FEATURE_NAME
108         pf: like parent_features; rf_count: INTEGER
109         precursor_feature: LIBERTY_FEATURE
110      do
111         create {HASHED_DICTIONARY[LIBERTY_FEATURE_DEFINITION, LIBERTY_FEATURE_NAME]} pf.with_capacity(parent.features.count)
112         from
113            i := parent.features.lower
114         until
115            i > parent.features.upper
116         loop
117            feature_name := parent.features.key(i)
118            parent_fd := parent.features.item(i)
119            check
120               parent_fd.current_type = parent
121            end
122            fd := parent_fd.specialized_in(type)
123            check
124               fd /= parent_fd
125            end
126            if fd.has_precursor(parent) then
127               breakpoint
128            else
129               precursor_feature := fd.the_feature.specialized_in(type)
130               fd.add_precursor(precursor_feature, parent)
131            end
132            pf.add(fd, feature_name)
133            i := i + 1
134         end
135         if clause /= Void and then clause.has_clauses then
136            rename_features(pf, clause.rename_clause, parent)
137            export_features(pf, clause.export_clause)
138            undefine_features(parent, pf, clause.undefine_clause)
139            rf_count := redefine_features(parent, pf, clause.redefine_clause)
140            if rf_count > 0 and then redefined_features.is_empty then
141               -- create a new collection because the default empty collection is shared
142               create {HASHED_DICTIONARY[LIBERTY_FEATURE_REDEFINED, LIBERTY_FEATURE_NAME]} redefined_features.with_capacity(rf_count)
143            end
144         end
145         from
146            i := pf.lower
147         until
148            i > pf.upper
149         loop
150            feature_name := pf.key(i)
151            fd := pf.item(i)
152            actual_fd := parent_features.reference_at(feature_name)
153            if actual_fd = Void then
154               parent_features.add(fd, feature_name)
155               debug ("type.building.internals")
156                  log.trace.put_string(once " <=> ")
157                  log.trace.put_string(parent.full_name)
158                  log.trace.put_string(once ": late binding down to ")
159                  log.trace.put_string(type.full_name)
160                  log.trace.put_string(once " of feature ")
161                  log.trace.put_line(feature_name.full_name)
162               end
163               precursor_feature := fd.the_feature.specialized_in(type)
164               check
165                  precursor_feature.current_type = type
166               end
167               fd.the_feature.bind(precursor_feature, type)
168               if not fd.has_precursor(parent) then
169                  fd.add_precursor(precursor_feature, parent)
170               end
171               actual_fd := fd
172            else
173               debug ("type.building.internals")
174                  log.trace.put_string(once " <=> ")
175                  log.trace.put_string(parent.full_name)
176                  log.trace.put_string(once ": joining in ")
177                  log.trace.put_string(type.full_name)
178                  log.trace.put_string(once " of feature ")
179                  log.trace.put_line(feature_name.full_name)
180               end
181               actual_fd.join(fd, parent)
182               check
183                  actual_fd.feature_name.is_equal(feature_name)
184               end
185               actual_fd.the_feature.bind(actual_fd.the_feature, type)
186            end
187            actual_fd.the_feature.add_if_redefined(type, feature_name, redefined_features)
188            check
189               actual_fd.has_precursor(parent)
190               actual_fd.the_feature.bound(type) = actual_fd.the_feature
191            end
192
193            i := i + 1
194         end
195      end
196
197   rename_features (pf: like parent_features; clause: LIBERTY_AST_PARENT_RENAME; parent: LIBERTY_ACTUAL_TYPE) is
198      local
199         i: INTEGER; r: LIBERTY_AST_RENAME; old_name, new_name: LIBERTY_FEATURE_NAME
200         fd, fd2: LIBERTY_FEATURE_DEFINITION
201      do
202         from
203            i := clause.list_lower
204         until
205            i > clause.list_upper
206         loop
207            r := clause.list_item(i)
208            create old_name.make_from_ast(r.old_name.feature_name_or_alias, type.ast, type.file)
209            create new_name.make_from_ast(r.new_name.feature_name_or_alias, type.ast, type.file)
210            fd := pf.reference_at(old_name)
211            if fd = Void then
212               errors.add_position(old_name.position)
213               errors.set(level_error, once "Cannot rename inexistent feature: " + old_name.name)
214            else
215               fd2 := pf.reference_at(new_name)
216               if fd2 = Void then
217                  pf.remove(old_name)
218                  fd.re_name(new_name)
219                  pf.add(fd, new_name)
220               else
221                  pf.remove(old_name)
222                  fd2.join(fd, parent)
223                  --|*** TODO: how to know that that particular join provoked an error?
224                  --if errors.has_error then
225                  --   errors.add_position(new_name.position)
226                  --   errors.set(level_error, once "Cannot rename feature (another feature with the same name exists): " + new_name.name)
227                  --end
228               end
229            end
230            i := i + 1
231         end
232      end
233
234   export_features (pf: like parent_features; clause: LIBERTY_AST_PARENT_EXPORT) is
235      local
236         i, j: INTEGER; e: LIBERTY_AST_EXPORT; ef: LIBERTY_AST_EXPORT_FEATURES; feature_name: LIBERTY_FEATURE_NAME; fn: LIBERTY_AST_FEATURE_NAME
237         clients: COLLECTION[LIBERTY_TYPE]
238         fd: LIBERTY_FEATURE_DEFINITION
239      do
240         from
241            i := clause.list_lower
242         until
243            i > clause.list_upper
244         loop
245            e := clause.list_item(i)
246            clients := list_clients(e.clients)
247            ef := e.features
248            if ef.is_all then
249               from
250                  j := pf.lower
251               until
252                  j > pf.upper
253               loop
254                  --|*** TODO: wrong! "all" should only change the clients of those not specifically changed.
255                  pf.item(j).set_clients(clients)
256                  j := j + 1
257               end
258            else
259               from
260                  j := ef.feature_names.lower
261               until
262                  j > ef.feature_names.upper
263               loop
264                  fn ::= ef.feature_names.item(j)
265                  create feature_name.make_from_ast(fn.feature_name_or_alias, type.ast, type.file)
266                  fd := pf.reference_at(feature_name)
267                  if fd = Void then
268                     errors.add_position(feature_name.position)
269                     errors.set(level_error, once "Cannot change export of inexistent feature: " + feature_name.name)
270                  else
271                     fd.set_clients(clients)
272                  end
273                  j := j + 1
274               end
275            end
276            i := i + 1
277         end
278      end
279
280   undefine_features (parent: LIBERTY_ACTUAL_TYPE; pf: like parent_features; clause: LIBERTY_AST_PARENT_UNDEFINE) is
281         -- replace the feature by a LIBERTY_FEATURE_DEFERRED
282      local
283         i: INTEGER; feature_name: LIBERTY_FEATURE_NAME; fd: LIBERTY_FEATURE_DEFINITION
284         inherited_feature: LIBERTY_FEATURE; deferred_feature: LIBERTY_FEATURE_DEFERRED
285      do
286         from
287            i := clause.list_lower
288         until
289            i > clause.list_upper
290         loop
291            create feature_name.make_from_ast(clause.list_item(i).feature_name_or_alias, type.ast, type.file)
292            fd := pf.reference_at(feature_name)
293            if fd = Void then
294               errors.add_position(feature_name.position)
295               errors.set(level_error, once "Cannot undefine inexistent feature: " + feature_name.name)
296            elseif fd.is_frozen then
297               errors.add_position(feature_name.position)
298               errors.set(level_error, once "Cannot undefine frozen feature: " + feature_name.name)
299            else
300               inherited_feature := fd.the_feature.specialized_in(type)
301               create deferred_feature.make(type)
302               deferred_feature.set_precondition(inherited_feature.precondition)
303               deferred_feature.set_postcondition(inherited_feature.postcondition)
304               deferred_feature.set_context(inherited_feature.context)
305               deferred_feature.set_type_resolver(inherited_feature.type_resolver, True)
306               debug ("type.building.internals")
307                  log.trace.put_string(once " <=> ")
308                  log.trace.put_string(parent.full_name)
309                  log.trace.put_string(once ": late binding down to ")
310                  log.trace.put_string(type.full_name)
311                  log.trace.put_string(once " of undefined feature ")
312                  log.trace.put_line(feature_name.full_name)
313               end
314               deferred_feature.replace(inherited_feature, type)
315               fd.set_the_feature(deferred_feature)
316            end
317            i := i + 1
318         end
319      end
320
321   redefine_features (parent: LIBERTY_ACTUAL_TYPE; pf: like parent_features; clause: LIBERTY_AST_PARENT_REDEFINE): INTEGER is
322         -- replace the feature by a LIBERTY_FEATURE_REDEFINED
323      local
324         i: INTEGER; feature_name: LIBERTY_FEATURE_NAME; fd: LIBERTY_FEATURE_DEFINITION
325         inherited_feature: LIBERTY_FEATURE; redefined_feature: LIBERTY_FEATURE
326      do
327         Result := clause.list_count
328         if Result > 0 then
329            from
330               i := clause.list_lower
331            until
332               i > clause.list_upper
333            loop
334               create feature_name.make_from_ast(clause.list_item(i).feature_name_or_alias, type.ast, type.file)
335               fd := pf.reference_at(feature_name)
336               if fd = Void then
337                  errors.add_position(feature_name.position)
338                  errors.set(level_error, once "Cannot redefine inexistent feature: " + feature_name.name)
339               elseif fd.is_frozen then
340                  errors.add_position(feature_name.position)
341                  errors.set(level_error, once "Cannot redefine frozen feature: " + feature_name.name)
342               else
343                  inherited_feature := fd.the_feature.specialized_in(type)
344                  if inherited_feature.bound(type).id = inherited_feature.id then
345                     create {LIBERTY_FEATURE_REDEFINED} redefined_feature.make(type)
346                     redefined_feature.set_precondition(inherited_feature.precondition)
347                     redefined_feature.set_postcondition(inherited_feature.postcondition)
348                     redefined_feature.set_context(inherited_feature.context)
349                     redefined_feature.set_type_resolver(inherited_feature.type_resolver, True)
350                     debug ("type.building.internals")
351                        log.trace.put_string(once " <=> ")
352                        log.trace.put_string(parent.full_name)
353                        log.trace.put_string(once ": late binding down to ")
354                        log.trace.put_string(type.full_name)
355                        log.trace.put_string(once " of redefined feature ")
356                        log.trace.put_line(feature_name.full_name)
357                     end
358                     redefined_feature.replace(inherited_feature, type)
359                  else
360                     --|*** TODO: ??? is it possible to have a non-related feature here???
361                     redefined_feature := inherited_feature.bound(type)
362                  end
363                  fd.set_the_feature(redefined_feature)
364               end
365
366               i := i + 1
367            end
368         end
369      end
370
371   push_parent_features_in_type is
372      local
373         i: INTEGER
374         fn, k: LIBERTY_FEATURE_NAME
375         f: LIBERTY_FEATURE_DEFINITION
376      do
377         from
378            i := parent_features.lower
379         until
380            i >  parent_features.upper
381         loop
382            f := parent_features.item(i)
383            fn := f.feature_name
384            debug
385               k := parent_features.key(i)
386               check
387                  fn.is_equal(k)
388               end
389            end
390            if not type.has_feature(fn) then
391               torch.burn
392               type.add_feature(f)
393            else
394               check
395                  type.features.reference_at(fn) = f
396               end
397            end
398            i := i + 1
399         end
400      end
401
402feature {}
403   parent_features: DICTIONARY[LIBERTY_FEATURE_DEFINITION, LIBERTY_FEATURE_NAME]
404   redefined_features: DICTIONARY[LIBERTY_FEATURE_REDEFINED, LIBERTY_FEATURE_NAME]
405   current_entity: LIBERTY_CURRENT
406
407invariant
408   parent_features /= Void
409   redefined_features /= Void
410
411end -- class LIBERTY_TYPE_PARENT_FEATURES_LOADER