PageRenderTime 26ms CodeModel.GetById 14ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 1ms

/src/tools/semantics/code/liberty_feature.e

http://github.com/tybor/Liberty
Specman e | 949 lines | 839 code | 81 blank | 29 comment | 52 complexity | 912f0b01addbbb6ff125da9dcd7e89d8 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--
 15deferred class LIBERTY_FEATURE
 16
 17inherit
 18   LIBERTY_TAGGED
 19      redefine
 20         is_equal
 21      end
 22
 23insert
 24   LIBERTY_REACHABLE_MARKED
 25      redefine
 26         is_equal
 27      end
 28   HASHABLE
 29   VISITABLE
 30      redefine
 31         is_equal
 32      end
 33   LOGGING
 34      redefine
 35         is_equal
 36      end
 37
 38feature {ANY}
 39   id: INTEGER
 40         -- The feature's unique id (does not change through specialization)
 41
 42   definition_type: LIBERTY_ACTUAL_TYPE
 43         -- The type where the feature is written
 44
 45   original: like Current
 46         -- The original feature in `definition_type', useful to tag things (such as once results...)
 47
 48   is_redefined: BOOLEAN
 49         -- True if this feature is proxied by a LIBERTY_REDEFINED_FEATURE and should not be used by itself.
 50
 51   current_type: LIBERTY_ACTUAL_TYPE is
 52      do
 53         Result := context.current_type
 54      end
 55
 56   result_type: LIBERTY_TYPE is
 57      require
 58         has_context
 59      do
 60         Result := context.result_type
 61      end
 62
 63   hash_code: INTEGER is
 64      do
 65         Result := id
 66      end
 67
 68   is_equal (other: like Current): BOOLEAN is
 69      do
 70         Result := id = other.id
 71      end
 72
 73   context: LIBERTY_FEATURE_DEFINITION_CONTEXT
 74   type_resolver: LIBERTY_TYPE_RESOLVER_IN_FEATURE
 75
 76   precondition: LIBERTY_REQUIRE
 77   postcondition: LIBERTY_ENSURE
 78
 79   obsolete_message: STRING
 80
 81   is_obsolete: BOOLEAN is
 82      do
 83         Result := obsolete_message /= Void
 84      end
 85
 86   parameters: TRAVERSABLE[LIBERTY_PARAMETER] is
 87      require
 88         has_context
 89      do
 90         Result := context.parameters
 91      ensure
 92         exists: Result /= Void
 93      end
 94
 95   has_context: BOOLEAN is
 96      do
 97         Result := context /= Void
 98      end
 99
100   has_accelerator: BOOLEAN is
101      do
102         Result := accelerator /= Void
103      end
104
105   accelerate_call (a: LIBERTY_FEATURE_ACCELERATOR) is
106      require
107         has_accelerator
108      do
109         accelerator.call([a, Current])
110      end
111
112feature {LIBERTY_REACHABLE, LIBERTY_REACHABLE_COLLECTION_MARKER}
113   mark_reachable_code (mark: like reachable_mark) is
114      do
115         if current_type.is_reachable then
116            if not is_reachable then
117               debug ("mark.reachable")
118                  log.trace.put_string(once "Marked reachable the feature: ")
119                  log.trace.put_line(out)
120               end
121               torch.burn
122            end
123            if reachable_mark < mark then
124               do_mark_reachable_code(mark)
125            end
126         end
127      end
128
129feature {}
130   do_mark_reachable_code (mark: like reachable_mark) is
131      require
132         current_type.is_reachable
133         reachable_mark < mark
134         mark > 0
135      local
136         i: INTEGER
137      do
138         reachable_mark := mark
139         if precondition /= Void then
140            precondition.mark_reachable_code(mark)
141         end
142         if postcondition /= Void then
143            postcondition.mark_reachable_code(mark)
144         end
145         from
146            i := child_bindings_memory.lower
147         until
148            i > child_bindings_memory.upper
149         loop
150            child_bindings_memory.item(i).mark_reachable_code(mark)
151            i := i + 1
152         end
153      ensure
154         reachable_mark >= mark
155      end
156
157feature {LIBERTY_FEATURE_ENTITY}
158   can_check_agent_signature (a_agent_call: LIBERTY_CALL_EXPRESSION): BOOLEAN is
159      require
160         a_agent_call /= Void
161      local
162         i: INTEGER
163      do
164         if result_type = Void or else result_type.is_known then
165            from
166               Result := a_agent_call.target = Void or else a_agent_call.target.is_open_argument
167               i := parameters.lower
168            until
169               not Result or else i > parameters.upper
170            loop
171               Result := parameters.item(i).result_type.is_known
172               i := i + 1
173            end
174         end
175      ensure
176         can_also_check_result_type: Result implies (result_type = Void or else result_type.is_known)
177      end
178
179   agent_signature (a_agent_call: LIBERTY_CALL_EXPRESSION): COLLECTION[LIBERTY_KNOWN_TYPE] is
180      require
181         can_check_agent_signature(a_agent_call)
182         a_agent_call.is_agent_call
183      local
184         i: INTEGER
185      do
186         if a_agent_call.target = Void or else not a_agent_call.target.is_open_argument then
187            create {FAST_ARRAY[LIBERTY_KNOWN_TYPE]} Result.with_capacity(parameters.count)
188         else
189            create {FAST_ARRAY[LIBERTY_KNOWN_TYPE]} Result.with_capacity(parameters.count + 1)
190            Result.add_last(current_type)
191         end
192         from
193            i := parameters.lower
194         until
195            i > parameters.upper
196         loop
197            Result.add_last(parameters.item(i).result_type.known_type)
198            i := i + 1
199         end
200      end
201
202   check_agent_signature (a_agent_call: LIBERTY_CALL_EXPRESSION) is
203      require
204         can_check_agent_signature(a_agent_call)
205         a_agent_call.is_agent_call
206      local
207         i, j: INTEGER
208      do
209         if a_agent_call.target = Void or else not a_agent_call.is_open_argument then
210            i := 0
211         else
212            if parameters.is_empty then
213               crash --| TODO: error, bad number of arguments
214            end
215            if not a_agent_call.target.result_type.known_type.is_conform_to(parameters.first.result_type.known_type)
216               and then not a_agent_call.target.result_type.known_type.converts_to(parameters.first.result_type.known_type) then
217               crash --| TODO: error, bad argument type
218            end
219            i := 1
220         end
221         if a_agent_call.actuals.count /= 0 then
222            if a_agent_call.actuals.count /= parameters.count + i then
223               crash --| TODO: error, bad number of arguments
224            end
225            from
226               i := parameters.lower + i
227               j := a_agent_call.actuals.lower
228            until
229               i > parameters.upper
230            loop
231               if not parameters.item(i).result_type.known_type.is_conform_to(a_agent_call.actuals.item(j).result_type.known_type)
232                  and then not parameters.item(i).result_type.known_type.converts_to(a_agent_call.actuals.item(j).result_type.known_type) then
233                  crash --| TODO: error, bad argument type
234               end
235               i := i + 1
236               j := j + 1
237            end
238         end
239      end
240
241feature {ANY}
242   frozen debug_display (o: OUTPUT_STREAM; tab: INTEGER) is
243      do
244         tabulate(o, tab)
245         do_debug_display(o, tab)
246         debug_display_bindings(o, tab)
247      end
248
249feature {LIBERTY_FEATURE}
250   do_debug_display (o: OUTPUT_STREAM; tab: INTEGER) is
251      local
252         t: STRING
253      do
254         o.put_character('{')
255         o.put_string(context.current_type.full_name)
256         o.put_string(once "->")
257         o.put_string(definition_type.full_name)
258         o.put_character('}')
259         o.put_character(' ')
260         t := generating_type
261         t := t.substring(17, t.upper)
262         t.to_lower
263         o.put_string(t)
264         context.debug_display_signature(o)
265         o.put_character(' ')
266         o.put_character('@')
267         o.put_line(to_pointer.out)
268      end
269
270   debug_display_bindings (o: OUTPUT_STREAM; tab: INTEGER) is
271      do
272         debug_display_parent_bindings(o, tab)
273         debug_display_child_bindings(o, tab)
274      end
275
276   debug_display_parent_bindings (o: OUTPUT_STREAM; tab: INTEGER) is
277      local
278         i: INTEGER
279      do
280         tabulate(o, tab)
281         o.put_line(once "Parent bindings:")
282         from
283            i := parent_bindings_memory.lower
284         until
285            i > parent_bindings_memory.upper
286         loop
287            tabulate(o, tab)
288            o.put_string(once " * ")
289            o.put_integer(i+1)
290            o.put_character('/')
291            o.put_integer(parent_bindings_memory.count)
292            o.put_string(once ": ")
293            parent_bindings_memory.item(i).do_debug_display(o, tab + 1)
294            --|*** TODO: looks like there is a parent cycle in NUMERIC.is_equal <-> COMPARABLE.is_equal
295            -- parent_bindings_memory.item(i).debug_display_parent_bindings(o, tab + 1)
296            i := i + 1
297         end
298      end
299
300   debug_display_child_bindings (o: OUTPUT_STREAM; tab: INTEGER) is
301      local
302         i: INTEGER
303      do
304         tabulate(o, tab)
305         o.put_line(once "Child bindings:")
306         from
307            i := child_bindings_memory.lower
308         until
309            i > child_bindings_memory.upper
310         loop
311            tabulate(o, tab)
312            o.put_string(once " * ")
313            o.put_integer(i)
314            o.put_character('/')
315            o.put_integer(child_bindings_memory.count)
316            o.put_string(once ": ")
317            o.put_string(child_bindings_memory.key(i).full_name)
318            o.put_string(once " => ")
319            child_bindings_memory.item(i).do_debug_display(o, tab + 1)
320            -- if child_bindings_memory.item(i) /= Current then
321            --    child_bindings_memory.item(i).debug_display_child_bindings(o, tab + 1)
322            -- end
323            i := i + 1
324         end
325      end
326
327   tabulate (o: OUTPUT_STREAM; tab: INTEGER) is
328      local
329         i: INTEGER
330      do
331         from
332            i := 1
333         until
334            i > tab
335         loop
336            o.put_string(once "   ")
337            i := i + 1
338         end
339      end
340
341feature {LIBERTY_FEATURE_DEFINITION}
342   join (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is
343      require
344         a_type /= Void
345         a_feature /= Void
346         current_fd.the_feature = Current
347         other_fd.the_feature = a_feature
348         not is_redefined
349      do
350         Result := do_join(a_type, a_feature, current_fd, other_fd)
351         bind_or_replace(Result, a_type, Result = Current)
352         a_feature.bind_or_replace(Result, a_type, Result = a_feature)
353      ensure
354         not errors.has_error implies Result /= Void
355      end
356
357feature {}
358   do_join (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is
359      require
360         a_type /= Void
361         a_feature /= Void
362         current_fd.the_feature = Current
363         other_fd.the_feature = a_feature
364      deferred
365      ensure
366         not errors.has_error implies Result /= Void
367      end
368
369feature {LIBERTY_FEATURE}
370   joined_attribute (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE_ATTRIBUTE; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is
371      require
372         a_type /= Void
373         a_feature /= Void
374         current_fd.the_feature = Current
375         other_fd.the_feature = a_feature
376      deferred
377      ensure
378         not errors.has_error implies Result /= Void
379      end
380
381   joined_constant (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE_CONSTANT; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is
382      require
383         a_type /= Void
384         a_feature /= Void
385         current_fd.the_feature = Current
386         other_fd.the_feature = a_feature
387      deferred
388      ensure
389         not errors.has_error implies Result /= Void
390      end
391
392   joined_deferred (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE_DEFERRED; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is
393      require
394         a_type /= Void
395         a_feature /= Void
396         current_fd.the_feature = Current
397         other_fd.the_feature = a_feature
398      deferred
399      ensure
400         not errors.has_error implies Result /= Void
401      end
402
403   joined_do (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE_DO; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is
404      require
405         a_type /= Void
406         a_feature /= Void
407         current_fd.the_feature = Current
408         other_fd.the_feature = a_feature
409      deferred
410      ensure
411         not errors.has_error implies Result /= Void
412      end
413
414   joined_external (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE_EXTERNAL; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is
415      require
416         a_type /= Void
417         a_feature /= Void
418         current_fd.the_feature = Current
419         other_fd.the_feature = a_feature
420      deferred
421      ensure
422         not errors.has_error implies Result /= Void
423      end
424
425   joined_once (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE_ONCE; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is
426      require
427         a_type /= Void
428         a_feature /= Void
429         current_fd.the_feature = Current
430         other_fd.the_feature = a_feature
431      deferred
432      ensure
433         not errors.has_error implies Result /= Void
434      end
435
436   joined_redefined (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE_REDEFINED; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is
437      require
438         a_type /= Void
439         a_feature /= Void
440         current_fd.the_feature = Current
441         other_fd.the_feature = a_feature
442      deferred
443      ensure
444         not errors.has_error implies Result /= Void
445      end
446
447   joined_unique (a_type: LIBERTY_ACTUAL_TYPE; a_feature: LIBERTY_FEATURE_UNIQUE; current_fd, other_fd: LIBERTY_FEATURE_DEFINITION): LIBERTY_FEATURE is
448      require
449         a_type /= Void
450         a_feature /= Void
451         current_fd.the_feature = Current
452         other_fd.the_feature = a_feature
453      deferred
454      ensure
455         not errors.has_error implies Result /= Void
456      end
457
458feature {ANY}
459   is_bound (type: LIBERTY_KNOWN_TYPE): BOOLEAN is
460      local
461         known: LIBERTY_ACTUAL_TYPE
462      do
463         if known ?:= type then
464            known ::= type
465            Result := child_bindings_memory.fast_has(known)
466         end
467      end
468
469   bound (type: LIBERTY_KNOWN_TYPE): LIBERTY_FEATURE is
470      local
471         known: LIBERTY_ACTUAL_TYPE
472      do
473         if known ?:= type then
474            known ::= type
475            Result := child_bindings_memory.fast_reference_at(known)
476         end
477         if Result = Void then
478            Result := Current
479         end
480      ensure
481         Result /= Void
482         not is_bound(type) implies Result = Current
483      end
484
485   specialized_in (a_type: LIBERTY_ACTUAL_TYPE): like Current is
486      do
487         if a_type = current_type or else not a_type.is_child_of(current_type) then
488            Result := Current
489         else
490            Result ::= specialized.fast_reference_at(a_type)
491            check
492               Result /= Current
493            end
494            if Result = Void then
495               is_specializing := True
496               Result := twin
497               is_specializing := False
498               specialized.add(Result, a_type)
499               Result.set_specialized_in(Current, context.specialized_in(a_type))
500               if not is_redefined then
501                  debug ("feature.specialization")
502                     log.trace.put_line(once "   Binding specialized feature")
503                  end
504                  bind_or_replace(Result, a_type, True)
505               end
506            end
507         end
508      ensure
509         Result.id = id
510         ;(current_type = a_type or not a_type.is_child_of(current_type)) implies Result = Current
511         ;(current_type /= a_type and a_type.is_child_of(current_type)) implies (Result /= Current and then Result.current_type = a_type)
512      end
513
514feature {LIBERTY_TYPE_PARENT_FEATURES_LOADER}
515   add_if_redefined (type: LIBERTY_ACTUAL_TYPE; name: LIBERTY_FEATURE_NAME; redefined_features: DICTIONARY[LIBERTY_FEATURE_REDEFINED, LIBERTY_FEATURE_NAME]) is
516      do
517         -- nothing
518      end
519
520feature {LIBERTY_FEATURE}
521   set_specialized_in (a_original: like Current; a_context: like context) is
522      require
523         is_specializing
524         a_original.id = id
525      do
526         original := a_original
527         context := a_context
528         check type_resolver /= Void end
529         create type_resolver.specialized(type_resolver.feature_name, Current, type_resolver.parent.specialized_in(a_context.current_type))
530         if precondition /= Void then
531            precondition := precondition.specialized_in(a_context.current_type)
532         end
533         if postcondition /= Void then
534            postcondition := postcondition.specialized_in(a_context.current_type)
535         end
536
537         -- Current is a twin of another feature, be sure to correctly create again the bindings
538         -- (avoid shared collections)
539         create {FAST_ARRAY[LIBERTY_FEATURE]} parent_bindings_memory.with_capacity(1)
540         create {HASHED_DICTIONARY[LIBERTY_FEATURE, LIBERTY_ACTUAL_TYPE]} child_bindings_memory.with_capacity(3)
541
542         is_specializing := False
543      ensure
544         original = a_original
545      end
546
547feature {LIBERTY_FEATURE}
548   has_parent_binding (a_parent: LIBERTY_FEATURE): BOOLEAN is
549      do
550         Result := Current = a_parent or else parent_bindings_memory.fast_has(a_parent)
551      end
552
553   add_parent_binding (a_parent: LIBERTY_FEATURE) is
554      require
555         a_parent /= Void
556         a_parent /= Current
557         not is_redefined
558      do
559         if has_parent_binding(a_parent) then
560            debug ("feature.binding")
561               log.trace.put_line(once "         => parent already added")
562            end
563         else
564            parent_bindings_memory.add_last(a_parent)
565            debug ("feature.binding")
566               log.trace.put_line(once "         => added parent to child")
567            end
568         end
569      end
570
571   remove_parent_binding (a_parent: LIBERTY_FEATURE) is
572      require
573         a_parent /= Current
574         has_parent_binding(a_parent)
575      local
576         i: INTEGER
577      do
578         i := parent_bindings_memory.fast_first_index_of(a_parent)
579         parent_bindings_memory.remove(i)
580      end
581
582   bind_or_replace (child: LIBERTY_FEATURE; type: LIBERTY_ACTUAL_TYPE; bind_current: BOOLEAN) is
583      require
584         not is_redefined
585         bind_current implies type = child.current_type
586         no_cycles: child /= Current implies not has_parent_binding(child)
587      local
588         i, j: INTEGER; removed: LIBERTY_FEATURE
589      do
590         check
591            child /= Current implies parent_bindings /= child.parent_bindings
592         end
593
594         if child /= Current and then child.has_parent_binding(Current) then
595            breakpoint
596         end
597
598         debug ("feature.binding")
599            log.trace.put_string(once "      Binding child: ")
600            child.do_debug_display(log.trace, 2)
601            if bind_current then
602               log.trace.put_string(once "      to Current: ")
603            else
604               log.trace.put_string(once "      replacing Current: ")
605            end
606            do_debug_display(log.trace, 2)
607         end
608
609         from
610            i := parent_bindings_memory.lower
611         until
612            i > parent_bindings_memory.upper
613         loop
614            debug ("feature.binding")
615               log.trace.put_string(once "       * Will bind parent #")
616               log.trace.put_integer(i+1)
617               log.trace.put_character('/')
618               log.trace.put_integer(parent_bindings_memory.count)
619               log.trace.put_string(once ": ")
620               parent_bindings_memory.item(i).do_debug_display(log.trace, 3)
621            end
622            removed := parent_bindings_memory.item(i).do_bind(child, Current, type)
623            if removed = Void then
624               i := i + 1
625            else
626               debug ("feature.binding")
627                  log.trace.put_line(once "         -> adding removed child's parents")
628               end
629               from
630                  j := removed.parent_bindings.lower
631               until
632                  j > removed.parent_bindings.upper
633               loop
634                  if removed.parent_bindings.item(j) /= Current then
635                     add_parent_binding(removed.parent_bindings.item(j))
636                  end
637                  j := j + 1
638               end
639            end
640         end
641
642         if bind_current then
643            debug ("feature.binding")
644               log.trace.put_string(once "       * Will bind Current: ")
645               do_debug_display(log.trace, 3)
646            end
647            removed := do_bind(child, Current, type)
648            check
649               removed /= Void implies removed.parent_bindings.is_empty -- i.e. removing a just-created feature, no precious data to be kept
650            end
651         end
652
653         debug ("feature.binding")
654            log.trace.put_string(once "   Final parent bindings of ")
655            child.do_debug_display(log.trace, 1)
656            from
657               i := child.parent_bindings.lower
658            until
659               i > child.parent_bindings.upper
660            loop
661               log.trace.put_string(once "    * ")
662               log.trace.put_integer(i+1)
663               log.trace.put_character('/')
664               log.trace.put_integer(child.parent_bindings.count)
665               log.trace.put_string(once ": ")
666               child.parent_bindings.item(i).do_debug_display(log.trace, 2)
667               i := i + 1
668            end
669         end
670      ensure
671         parent_bindings_memory.for_all(agent (c, p: LIBERTY_FEATURE): BOOLEAN is
672            do
673               debug ("feature.binding")
674                  log.trace.put_string(once "   Checking ")
675                  p.do_debug_display(log.trace, 1)
676               end
677               Result := c.has_parent_binding(p)
678               if not Result then
679                  breakpoint
680               end
681            end (child, ?)
682         )
683         parent_bindings_memory.for_all(agent (c, p: LIBERTY_FEATURE; t: LIBERTY_ACTUAL_TYPE): BOOLEAN is
684            do
685               Result := p.is_bound(t) and then bound(t) = c
686               if not Result then
687                  breakpoint
688               end
689            end (child, ?, type)
690         )
691      end
692
693   do_bind (child, target: LIBERTY_FEATURE; type: LIBERTY_ACTUAL_TYPE): LIBERTY_FEATURE is
694         -- Returns the replaced child if it exists
695      require
696         child /= Current implies not has_parent_binding(child)
697         not is_redefined
698      do
699         Result := child_bindings_memory.fast_reference_at(type)
700         if Result = child then
701            check
702               Result.has_parent_binding(Current)
703            end
704            debug ("feature.binding")
705               log.trace.put_line(once "         -> already bound.")
706            end
707            Result := Void
708         else
709            if Result /= Void then
710               debug ("feature.binding")
711                  log.trace.put_string(once "         -> remove old child: ")
712                  Result.do_debug_display(log.trace, 4)
713               end
714               child_bindings_memory.fast_remove(type)
715               Result.remove_parent_binding(Current)
716            else
717               check
718                  not child_bindings_memory.fast_has(type)
719               end
720            end
721            debug ("feature.binding")
722               log.trace.put_line(once "         -> adding new child")
723            end
724            child_bindings_memory.add(child, type)
725            if child /= Current then
726               child.add_parent_binding(Current)
727            end
728         end
729      end
730
731   parent_bindings: TRAVERSABLE[LIBERTY_FEATURE] is
732         -- Flat structure: all parents of the feature are here.
733      do
734         Result := parent_bindings_memory
735      end
736
737   child_bindings: MAP[LIBERTY_FEATURE, LIBERTY_ACTUAL_TYPE] is
738         -- Flat structure: all heirs of the feature are here.
739      do
740         Result := child_bindings_memory
741      end
742
743feature {LIBERTY_BUILDER_TOOLS}
744   bind (child: LIBERTY_FEATURE; type: LIBERTY_ACTUAL_TYPE) is
745      require
746         not is_redefined
747         truly_bind: child /= Current implies child.current_type /= current_type
748         no_cycles: child /= Current implies not has_parent_binding(child)
749         bind_current: type = child.current_type
750      do
751         bind_or_replace(child, type, True)
752      ensure
753         parent_bindings_memory.is_equal(old parent_bindings_memory.twin)
754         child.has_parent_binding(Current)
755         is_bound(type) and then bound(type) = child
756      end
757
758   replace (new: LIBERTY_FEATURE; type: LIBERTY_ACTUAL_TYPE) is
759      require
760         not new.is_redefined
761         truly_replace: new /= Current and then new.current_type = current_type
762         no_cycles: not new.has_parent_binding(Current)
763      do
764         is_specializing := True -- well, not exactly- but Current is dead, baby.
765         new.bind_or_replace(Current, type, False)
766      end
767
768feature {LIBERTY_FEATURE_DEFINITION_CONTEXT}
769   find_precursor (a_parent: LIBERTY_ACTUAL_TYPE): LIBERTY_FEATURE is
770      do
771         if a_parent = Void then
772            Result := find_closest_precursor
773         else
774            Result := find_parent_precursor(a_parent)
775         end
776         Result := Result.specialized_in(current_type)
777      end
778
779feature {}
780   find_closest_precursor: LIBERTY_FEATURE is
781      local
782         i: INTEGER; candidate: LIBERTY_FEATURE
783      do
784         from
785            i := parent_bindings_memory.lower
786         until
787            i > parent_bindings_memory.upper
788         loop
789            candidate := parent_bindings_memory.item(i)
790            if Result = Void or else candidate.current_type.is_child_of(Result.current_type) then
791               Result := candidate
792            end
793            i := i + 1
794         end
795      ensure
796         Result /= Void
797         Result /= Current
798      end
799
800   find_parent_precursor (a_parent: LIBERTY_ACTUAL_TYPE): LIBERTY_FEATURE is
801      require
802         a_parent /= Void
803      local
804         i: INTEGER; candidate: LIBERTY_FEATURE
805      do
806         from
807            i := parent_bindings_memory.lower
808         until
809            i > parent_bindings_memory.upper
810         loop
811            candidate := parent_bindings_memory.item(i)
812            if candidate.current_type = a_parent or else candidate.current_type.is_child_of(a_parent) then
813               if Result = Void or else candidate.current_type.is_child_of(Result.current_type) then
814                  Result := candidate
815               end
816            end
817            i := i + 1
818         end
819      ensure
820         Result /= Void
821         Result /= Current
822      end
823
824feature {LIBERTY_BUILDER_TOOLS, LIBERTY_FEATURE_DEFINITION}
825   set_type_resolver (a_type_resolver: like type_resolver; a_replace: BOOLEAN) is
826      require
827         a_type_resolver.local_context = context
828         a_type_resolver.the_feature /= Void implies a_replace
829         type_resolver = Void
830      do
831         if a_replace or else a_type_resolver.the_feature = Void then
832            a_type_resolver.set_the_feature(Current, a_replace)
833         end
834         type_resolver := a_type_resolver
835      ensure
836         type_resolver = a_type_resolver
837         a_replace implies type_resolver.the_feature = Current
838      end
839
840   set_context (a_context: like context) is
841      require
842         a_context /= Void
843      do
844         context := a_context
845      ensure
846         context = a_context
847      end
848
849   set_precondition (assertions: like precondition) is
850      do
851         precondition := assertions
852      ensure
853         precondition = assertions
854      end
855
856   set_postcondition (assertions: like postcondition) is
857      do
858         postcondition := assertions
859      ensure
860         postcondition = assertions
861      end
862
863   set_obsolete (a_obsolete: like obsolete_message) is
864      do
865         obsolete_message := a_obsolete
866      ensure
867         a_obsolete /= Void implies is_obsolete
868         obsolete_message = a_obsolete
869      end
870
871feature {LIBERTY_FEATURE_REDEFINED}
872   set_is_redefined is
873      do
874         is_redefined := True
875      end
876
877feature {}
878   make (a_definition_type: like definition_type; a_accelerator: like accelerator) is
879      require
880         a_definition_type /= Void
881      do
882         create {FAST_ARRAY[LIBERTY_FEATURE]} parent_bindings_memory.with_capacity(1)
883         definition_type := a_definition_type
884         create {HASHED_DICTIONARY[LIBERTY_FEATURE, LIBERTY_ACTUAL_TYPE]} child_bindings_memory.with_capacity(3)
885         create {HASHED_DICTIONARY[LIBERTY_FEATURE, LIBERTY_ACTUAL_TYPE]} specialized.with_capacity(3)
886         accelerator := a_accelerator
887
888         ids_provider.increment
889         id := ids_provider.value
890         original := Current
891      ensure
892         definition_type = a_definition_type
893         accelerator = a_accelerator
894         original = Current
895      end
896
897   parent_bindings_memory: COLLECTION[LIBERTY_FEATURE]
898   child_bindings_memory: DICTIONARY[LIBERTY_FEATURE, LIBERTY_ACTUAL_TYPE]
899
900   accelerator: PROCEDURE[TUPLE[LIBERTY_FEATURE_ACCELERATOR, LIBERTY_FEATURE]]
901   specialized: DICTIONARY[LIBERTY_FEATURE, LIBERTY_ACTUAL_TYPE]
902
903   errors: LIBERTY_ERRORS
904   torch: LIBERTY_ENLIGHTENING_THE_WORLD
905
906   is_specializing: BOOLEAN
907
908   ids_provider: COUNTER is
909      once
910         create Result
911      end
912
913invariant
914   child_bindings_memory /= Void
915   specialized /= Void
916   definition_type /= Void
917   parent_bindings_memory /= Void
918   original.id = id
919
920   context = Void implies parent_bindings_memory.is_empty
921   is_redefined implies (parent_bindings_memory.is_empty and child_bindings_memory.is_empty)
922
923   not is_specializing implies child_bindings_memory.for_all(agent (c: LIBERTY_FEATURE): BOOLEAN is
924      do
925         Result := c.has_parent_binding(Current)
926         if not Result then
927            breakpoint
928         end
929      end
930   )
931
932   not parent_bindings_memory.fast_has(Current)
933   not is_specializing implies parent_bindings_memory.for_all(agent (p: LIBERTY_FEATURE): BOOLEAN is
934      local
935         c: LIBERTY_FEATURE
936      do
937         if p.is_bound(current_type) then
938            c := p.bound(current_type)
939            Result := c = Current -- should be "c = Current" but for the `specialized_in' twin
940            if not Result then
941               breakpoint
942            end
943         else
944            Result := True
945         end
946      end
947   )
948
949end -- class LIBERTY_FEATURE