home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 3 / AACD03.BIN / AACD / Programming / sofa / archive / SmallEiffel.lha / SmallEiffel / lib_se / parent.e < prev    next >
Text File  |  1999-06-05  |  20KB  |  683 lines

  1. --          This file is part of SmallEiffel The GNU Eiffel Compiler.
  2. --          Copyright (C) 1994-98 LORIA - UHP - CRIN - INRIA - FRANCE
  3. --            Dominique COLNET and Suzanne COLLIN - colnet@loria.fr
  4. --                       http://SmallEiffel.loria.fr
  5. -- SmallEiffel is  free  software;  you can  redistribute it and/or modify it
  6. -- under the terms of the GNU General Public License as published by the Free
  7. -- Software  Foundation;  either  version  2, or (at your option)  any  later
  8. -- version. SmallEiffel is distributed in the hope that it will be useful,but
  9. -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  10. -- or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU General Public License
  11. -- for  more  details.  You  should  have  received a copy of the GNU General
  12. -- Public  License  along  with  SmallEiffel;  see the file COPYING.  If not,
  13. -- write to the  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  14. -- Boston, MA 02111-1307, USA.
  15. --
  16. class PARENT
  17.    --
  18.    -- To store the inheritance options for one parent of a class.
  19.    --
  20.  
  21. inherit GLOBALS;
  22.  
  23. creation make
  24.  
  25. feature {PARENT}
  26.  
  27.    parent_list: PARENT_LIST;
  28.          -- Corresponding one;
  29.  
  30. feature {PARENT,TYPE}
  31.  
  32.    type: TYPE;
  33.          -- Declaration type mark of the parent.
  34.  
  35. feature {NONE}
  36.  
  37.    comment: COMMENT;
  38.          -- Associated heading comment.
  39.  
  40. feature {PARENT} -- Optionnal list in syntaxical order :
  41.  
  42.    rename_list: RENAME_LIST;
  43.  
  44.    export_list: EXPORT_LIST;
  45.  
  46.    undefine_list: FEATURE_NAME_LIST
  47.  
  48.    redefine_list: FEATURE_NAME_LIST;
  49.  
  50.    select_list: FEATURE_NAME_LIST;
  51.  
  52. feature {NONE}
  53.  
  54.    make(t: like type) is
  55.       require
  56.          t /= Void;
  57.          not t.is_anchored;
  58.          t.start_position /= Void;
  59.       do
  60.          type := t;
  61.          if forbidden_parent_list.fast_has(type.written_mark) then
  62.             eh.add_position(type.start_position);
  63.             eh.append("You cannot inherit %"");
  64.             eh.append(type.written_mark);
  65.             fatal_error("%" (not yet implemented).");
  66.          end;
  67.       ensure
  68.          type = t
  69.       end;
  70.  
  71. feature {PARENT_LIST}
  72.  
  73.    start_position: POSITION is
  74.       do
  75.          Result := type.start_position;
  76.       end;
  77.  
  78.    base_class: BASE_CLASS is
  79.       do
  80.          Result := type.base_class;
  81.       end;
  82.  
  83.    name_in_parent(fn: FEATURE_NAME): FEATURE_NAME is
  84.          -- Gives Void or the name of `fn' before renaming.
  85.       do
  86.          if rename_list = Void then
  87.             Result := fn;
  88.          else
  89.             Result := rename_list.name_in_parent(fn);
  90.          end;
  91.       end;
  92.  
  93.    do_rename(fn: FEATURE_NAME): like fn is
  94.       do
  95.          if rename_list = Void then
  96.             Result := fn;
  97.          else
  98.             Result := rename_list.name_in_child(fn);
  99.          end;
  100.       end;
  101.  
  102.    has_redefine(fn: FEATURE_NAME): BOOLEAN is
  103.       do
  104.          if redefine_list /= Void then
  105.             Result := redefine_list.has(fn);
  106.          end;
  107.       end;
  108.  
  109.    look_up_for(rc: RUN_CLASS; fn: FEATURE_NAME): E_FEATURE is
  110.       require
  111.          rc /= Void;
  112.          fn /= Void
  113.       local
  114.          pfn: like fn;
  115.       do
  116.          if rename_list = Void then
  117.             Result := type.look_up_for(rc,fn);
  118.             Result := apply_undefine(Result,fn);
  119.          else
  120.             pfn := rename_list.name_in_parent(fn);
  121.             if pfn /= Void then
  122.                Result := type.look_up_for(rc,pfn);
  123.                Result := apply_undefine(Result,fn);
  124.             end;
  125.          end;
  126.       end;
  127.  
  128.    precursor_for(p: E_PRECURSOR; wrf: RUN_FEATURE): EFFECTIVE_ROUTINE is
  129.          -- Look for the feature for `p' which is written inside
  130.          -- `wrf'.
  131.       local
  132.          original_fn: FEATURE_NAME;
  133.          cn: CLASS_NAME;
  134.       do
  135.          original_fn := wrf.base_feature.first_name;
  136.          if has_redefine(original_fn) then
  137.             cn := p.parent;
  138.             if (cn = Void
  139.                 or else
  140.                 cn.to_string = type.base_class_name.to_string)
  141.              then
  142.                Result ?= look_up_for(wrf.run_class,original_fn);
  143.             end;
  144.          end;
  145.       end;
  146.  
  147.    multiple_check(other: like Current) is
  148.          -- Note : is called twice (whith swap) for each couple of
  149.          -- parents.
  150.       require
  151.          other /= Current
  152.       local
  153.          bc1, bc2: BASE_CLASS;
  154.          i: INTEGER;
  155.          fn1, fn2: FEATURE_NAME;
  156.       do
  157.          check
  158.             parent_list = other.parent_list
  159.          end;
  160.          bc1 := type.base_class;
  161.          bc2 := other.type.base_class;
  162.          if bc1 = bc2 or else
  163.             bc1.is_subclass_of(bc2) or else
  164.             bc2.is_subclass_of(bc1)
  165.           then
  166.             if redefine_list /= Void then
  167.                from
  168.                   i := redefine_list.count
  169.                until
  170.                   i = 0
  171.                loop
  172.                   fn1 := redefine_list.item(i);
  173.                   if other.rename_list = Void then
  174.                   else
  175.                      fn2 := other.rename_list.name_in_child(fn1);
  176.                      if fn2 /= fn1 then
  177.                         if select_list /= Void then
  178.                            if select_list.has(fn1) then
  179.                               if other.select_list /= Void then
  180.                                  if other.select_list.has(fn2) then
  181.                                     select_conflict(fn1,fn2);
  182.                                  end;
  183.                               end;
  184.                            elseif other.select_list = Void then
  185.                               missing_select(fn1,fn2);
  186.                            elseif not other.select_list.has(fn2) then
  187.                               missing_select(fn1,fn2);
  188.                            end;
  189.                         elseif other.select_list = Void then
  190.                            missing_select(fn1,fn2);
  191.                         elseif not other.select_list.has(fn2) then
  192.                            missing_select(fn1,fn2);
  193.                         end;
  194.                      end;
  195.                   end;
  196.                   i := i - 1;
  197.                end;
  198.             end;
  199.          else
  200.             -- Nothing because of swapped duplicate call.
  201.          end;
  202.       end;
  203.  
  204.    runnable_type(ct: TYPE): TYPE is
  205.       require
  206.          ct.is_run_type
  207.       do
  208.          if type.is_generic then
  209.             Result := type.to_runnable(ct);
  210.          else
  211.             Result := type;
  212.          end;
  213.       ensure
  214.          Result.is_run_type
  215.       end;
  216.  
  217.    is_a_vncg(t1, t2: TYPE): BOOLEAN is
  218.       require
  219.          t1.run_type = t1;
  220.          t2.run_type = t2;
  221.          t2.generic_list /= Void;
  222.          eh.empty
  223.       local
  224.          rank, i: INTEGER;
  225.          gl, gl1, gl2: ARRAY[TYPE];
  226.          tfg: TYPE_FORMAL_GENERIC;
  227.          rt: TYPE;
  228.          type_bc, t2_bc: BASE_CLASS;
  229.          type_bcn, t2_bcn: STRING;
  230.       do
  231.          type_bc := type.base_class;
  232.          type_bcn := type_bc.name.to_string;
  233.          t2_bc := t2.base_class;
  234.          t2_bcn := t2_bc.name.to_string;
  235.          if type_bcn = t2_bcn then -- Here is a good parent :
  236.             gl := type.generic_list;
  237.             gl2 := t2.generic_list;
  238.             if gl = Void or else gl.count /= gl2.count then
  239.                eh.add_position(type.start_position);
  240.                eh.add_position(t2.start_position);
  241.                fatal_error("Bad number of generic arguments.");
  242.             end;
  243.             if t1.is_generic then
  244.                gl1 := t1.generic_list;
  245.                from
  246.                   Result := true;
  247.                   i := gl2.count;
  248.                until
  249.                   not Result or else i = 0
  250.                loop
  251.                   if gl.item(i).is_formal_generic then
  252.                      tfg ?= gl.item(i);
  253.                      check
  254.                         tfg /= Void
  255.                      end;
  256.                      rank := tfg.rank;
  257.                      Result :=  gl1.item(rank).is_a(gl2.item(i));
  258.                   else
  259.                      rt := gl.item(i).to_runnable(t1).run_type;
  260.                      Result := rt.is_a(gl2.item(i));
  261.                   end;
  262.                   i := i - 1;
  263.                end;
  264.             else
  265.                Result := type.is_a(t2);
  266.             end;
  267.             if not Result then
  268.                eh.cancel;
  269.             end;
  270.          elseif type_bc.is_subclass_of(t2_bc) then
  271.             if t1.is_generic then
  272.                rt := type.to_runnable(t1).run_type;
  273.                Result := type_bc.is_a_vncg(rt,t2);
  274.             else
  275.                Result := type_bc.is_a_vncg(type,t2);
  276.             end;
  277.             if not Result then
  278.                eh.cancel;
  279.             end;
  280.          end;
  281.       ensure
  282.          eh.empty
  283.       end;
  284.  
  285.    e_feature(fn: FEATURE_NAME): E_FEATURE is
  286.       local
  287.          fn2: FEATURE_NAME;
  288.       do
  289.          if rename_list = Void then
  290.             Result := type.base_class.e_feature(fn);
  291.          else
  292.             fn2 := rename_list.name_in_parent(fn);
  293.             if fn2 /= Void then
  294.                Result := type.base_class.e_feature(fn2);
  295.             end;
  296.          end;
  297.       end;
  298.  
  299.    clients_for(fn: FEATURE_NAME): CLIENT_LIST is
  300.       require
  301.          fn /= Void
  302.       local
  303.          fn2: like fn;
  304.       do
  305.          if rename_list = Void then
  306.             Result := consider_export(fn);
  307.          else
  308.             fn2 := rename_list.name_in_parent(fn);
  309.             if fn2 /= Void then
  310.                Result := consider_export(fn2);
  311.             end;
  312.          end;
  313.       end;
  314.  
  315.    pretty_print is
  316.       local
  317.          end_needed: BOOLEAN;
  318.       do
  319.          fmt.set_indent_level(1);
  320.          fmt.indent;
  321.          type.pretty_print;
  322.          if rename_list = Void and then
  323.             export_list = Void and then
  324.             undefine_list = Void and then
  325.             redefine_list = Void and then
  326.             select_list = Void then
  327.             fmt.put_character(';');
  328.          end;
  329.          if comment /= Void then
  330.             fmt.put_character(' ');
  331.             comment.pretty_print;
  332.          end;
  333.          if rename_list /= Void then
  334.             end_needed := true;
  335.             rename_list.pretty_print;
  336.          end;
  337.          if export_list /= Void then
  338.             end_needed := true;
  339.             export_list.pretty_print;
  340.          end;
  341.          if undefine_list /= Void then
  342.             end_needed := true;
  343.             fmt.set_indent_level(2);
  344.             fmt.indent;
  345.             fmt.keyword("undefine");
  346.             undefine_list.pretty_print;
  347.          end;
  348.          if redefine_list /= Void then
  349.             end_needed := true;
  350.             fmt.set_indent_level(2);
  351.             fmt.indent;
  352.             fmt.keyword("redefine");
  353.             redefine_list.pretty_print;
  354.          end;
  355.          if select_list /= Void then
  356.             end_needed := true;
  357.             fmt.set_indent_level(2);
  358.             fmt.indent;
  359.             fmt.keyword("select");
  360.             select_list.pretty_print;
  361.          end;
  362.          if end_needed then
  363.             fmt.set_indent_level(2);
  364.             fmt.indent;
  365.             fmt.keyword("end;");
  366.          end;
  367.          fmt.set_indent_level(1);
  368.          fmt.indent;
  369.       end;
  370.  
  371.    get_started(pl: like parent_list) is
  372.       require
  373.          pl /= Void;
  374.       local
  375.          i: INTEGER;
  376.          wbc, pbc: BASE_CLASS;
  377.          fn, old_fn, new_fn: FEATURE_NAME;
  378.          all_check: BOOLEAN;
  379.       do
  380.          all_check := run_control.all_check;
  381.          parent_list := pl;
  382.          pbc := type.base_class;
  383.          wbc := parent_list.base_class;
  384.          if all_check then
  385.             if pbc.formal_generic_list /= Void then
  386.                if type.generic_list = Void then
  387.                   -- Nothing, because previous call triggers an error message.
  388.                end;
  389.             elseif type.is_generic then
  390.                eh.add_position(pbc.name.start_position);
  391.                eh.add_position(type.start_position);
  392.                fatal_error("This class is not generic (VTUG.1).");
  393.             end;
  394.          end;
  395.          if all_check and then rename_list /= Void then
  396.             rename_list.get_started(pbc);
  397.          end;
  398.          if all_check and then undefine_list /= Void then
  399.             from
  400.                i := undefine_list.count;
  401.             until
  402.                i = 0
  403.             loop
  404.                fn := undefine_list.item(i);
  405.                old_fn := get_old_name(fn);
  406.                if old_fn = Void and then not pbc.has(fn) then
  407.                   eh.add_position(fn.start_position);
  408.                   fatal_error("Cannot undefine unexistant feature (VDUS.1).");
  409.                end;
  410.                i := i - 1;
  411.             end;
  412.          end;
  413.          if redefine_list /= Void then
  414.             from
  415.                i := redefine_list.count;
  416.             until
  417.                i = 0
  418.             loop
  419.                fn := redefine_list.item(i);
  420.                if not wbc.proper_has(fn) then
  421.                   eh.add_position(fn.start_position);
  422.                   fatal_error("Redefinition not found.");
  423.                end;
  424.                if all_check then
  425.                   old_fn := get_old_name(fn);
  426.                   if old_fn = Void and then not pbc.has(fn) then
  427.                      eh.add_position(fn.start_position);
  428.                      fatal_error(Vdrs1);
  429.                   end;
  430.                   new_fn := get_new_name(fn);
  431.                   if new_fn /= Void then
  432.                      eh.add_position(new_fn.start_position);
  433.                      eh.add_position(fn.start_position);
  434.                      fatal_error(Vdrs1);
  435.                   end;
  436.                end;
  437.                i := i - 1;
  438.             end;
  439.          end;
  440.          if all_check and then select_list /= Void then
  441.             from
  442.                i := select_list.count;
  443.             until
  444.                i = 0
  445.             loop
  446.                fn := select_list.item(i);
  447.                old_fn := get_old_name(fn);
  448.                if old_fn = Void and then not pbc.has(fn) then
  449.                   eh.add_position(fn.start_position);
  450.                   fatal_error(Vmss);
  451.                end;
  452.                new_fn := get_new_name(fn);
  453.                if new_fn /= Void then
  454.                   if get_old_name(new_fn) = Void then
  455.                      eh.add_position(new_fn.start_position);
  456.                      eh.add_position(fn.start_position);
  457.                      fatal_error(Vmss);
  458.                   end;
  459.                end;
  460.                i := i - 1;
  461.             end;
  462.          end;
  463.       ensure
  464.          parent_list = pl
  465.       end;
  466.  
  467.    up_to_original(bottom: BASE_CLASS; top_fn: FEATURE_NAME): FEATURE_NAME is
  468.       local
  469.          old_name: FEATURE_NAME;
  470.          bc: BASE_CLASS;
  471.       do
  472.          bc := type.base_class;
  473.          if rename_list = Void then
  474.             Result := bc.up_to_original(bottom,top_fn);
  475.          else
  476.             old_name := rename_list.name_in_parent(top_fn);
  477.             if old_name /= Void then
  478.                Result := bc.up_to_original(bottom,old_name);
  479.             end;
  480.          end;
  481.       end;
  482.  
  483.    going_up(trace: FIXED_ARRAY[PARENT]; top: BASE_CLASS;
  484.             top_fn: FEATURE_NAME;): FEATURE_NAME is
  485.       local
  486.          bc: BASE_CLASS;
  487.       do
  488.          bc := type.base_class;
  489.          if bc = top then
  490.             Result := going_down(trace,top_fn);
  491.          elseif bc.is_general then
  492.             Result := going_down(trace,top_fn);
  493.          elseif bc.is_subclass_of(top) then
  494.             trace.add_last(Current);
  495.             Result := bc.going_up(trace,top,top_fn);
  496.          end;
  497.       end;
  498.  
  499.    has_select_for(fn: FEATURE_NAME): BOOLEAN is
  500.       do
  501.          if select_list /= Void then
  502.             Result := select_list.has(fn);
  503.          end;
  504.       end;
  505.  
  506. feature {EIFFEL_PARSER}
  507.  
  508.    set_comment(c: like comment) is
  509.       do
  510.          comment := c;
  511.       end;
  512.  
  513.    add_rename(rp: RENAME_PAIR) is
  514.       require
  515.          rp /= Void
  516.       do
  517.          if rename_list = Void then
  518.             !!rename_list.make(<<rp>>);
  519.          else
  520.             rename_list.add_last(rp);
  521.          end;
  522.       end;
  523.  
  524.    set_export(el: EXPORT_LIST) is
  525.       require
  526.          el /= Void
  527.       do
  528.          export_list := el;
  529.       ensure
  530.          export_list = el
  531.       end;
  532.  
  533.    set_undefine(ul: FEATURE_NAME_LIST) is
  534.       do
  535.          undefine_list := ul;
  536.       ensure
  537.          undefine_list = ul
  538.       end;
  539.  
  540.    set_redefine(rl: FEATURE_NAME_LIST) is
  541.       do
  542.          redefine_list := rl;
  543.       ensure
  544.          redefine_list = rl
  545.       end;
  546.  
  547.    set_select(sl: like select_list) is
  548.       do
  549.          select_list := sl;
  550.       ensure
  551.          select_list = sl
  552.       end;
  553.  
  554. feature {PARENT}
  555.  
  556.    going_down(trace: FIXED_ARRAY[PARENT]; fn: FEATURE_NAME;): FEATURE_NAME is
  557.       require
  558.          trace /= Void;
  559.          fn /= Void
  560.       local
  561.          previous: like Current;
  562.       do
  563.          if rename_list = Void then
  564.             Result := fn;
  565.          else
  566.             Result := rename_list.name_in_child(fn);
  567.          end;
  568.          if not trace.empty then
  569.             previous := trace.last;
  570.             trace.remove_last;
  571.             Result := previous.going_down(trace,Result);
  572.          end;
  573.       ensure
  574.          Result /= Void
  575.       end;
  576.  
  577. feature {NONE}
  578.  
  579.    forbidden_parent_list: ARRAY[STRING] is
  580.       once
  581.          Result := <<as_none,as_boolean,as_integer,as_character,
  582.                      as_real,as_double,as_bit,as_pointer,
  583.                      as_native_array>>;
  584.       end;
  585.  
  586.    get_old_name(fn: FEATURE_NAME): like fn is
  587.       do
  588.          if rename_list /= Void then
  589.             Result := rename_list.name_in_parent(fn);
  590.             if Result = fn then
  591.                Result := Void;
  592.             end;
  593.          end;
  594.       end;
  595.  
  596.    get_new_name(fn: FEATURE_NAME): like fn is
  597.       do
  598.          if rename_list /= Void then
  599.             Result := rename_list.name_in_child(fn);
  600.             if Result = fn then
  601.                Result := Void;
  602.             end;
  603.          end;
  604.       end;
  605.  
  606.    apply_undefine(f: E_FEATURE; fn: FEATURE_NAME): E_FEATURE is
  607.       local
  608.          ufn: FEATURE_NAME;
  609.          fnkey: STRING;
  610.          index: INTEGER;
  611.       do
  612.          ufn := has_undefine(fn);
  613.          if ufn /= Void then
  614.             if undefine_memory1 = Void then
  615.                !!undefine_memory1.with_capacity(undefine_list.count);
  616.                !!undefine_memory2.with_capacity(undefine_list.count);
  617.             end;
  618.             fnkey := ufn.to_key;
  619.             index := undefine_memory1.fast_index_of(fnkey);
  620.             if index > undefine_memory1.upper then
  621.                undefine_memory1.add_last(fnkey);
  622.                Result := f.try_to_undefine(ufn,parent_list.base_class);
  623.                undefine_memory2.add_last(Result);
  624.             else
  625.                Result := undefine_memory2.item(index);
  626.             end;
  627.          else
  628.             Result := f;
  629.          end;
  630.       end;
  631.  
  632.    undefine_memory1: FIXED_ARRAY[STRING];
  633.  
  634.    undefine_memory2: FIXED_ARRAY[E_FEATURE];
  635.  
  636.    has_undefine(fn: FEATURE_NAME): FEATURE_NAME is
  637.       do
  638.          if undefine_list /= Void then
  639.             Result := undefine_list.feature_name(fn.to_key);
  640.          end;
  641.       end;
  642.  
  643.    select_conflict(fn1, fn2: FEATURE_NAME) is
  644.       do
  645.          eh.add_position(fn1.start_position)
  646.          eh.add_position(fn2.start_position)
  647.          fatal_error("Select conflict for these features.");
  648.       end;
  649.  
  650.    missing_select(fn1, fn2: FEATURE_NAME) is
  651.       do
  652.          eh.add_position(fn1.start_position)
  653.          eh.add_position(fn2.start_position)
  654.          fatal_error("Missing select clause for these features.");
  655.       end;
  656.  
  657.    Vmss: STRING is "Cannot select unexistant feature (VMSS).";
  658.  
  659.    Vdrs1: STRING is "Cannot redefine unexistant feature (VDRS.1).";
  660.  
  661.    consider_export(fn: FEATURE_NAME): CLIENT_LIST is
  662.       require
  663.          fn /= Void
  664.       do
  665.          if export_list = Void then
  666.             Result := type.base_class.clients_for(fn);
  667.          else
  668.             Result := export_list.clients_for(fn);
  669.             if Result = Void then
  670.                Result := type.base_class.clients_for(fn);
  671.             end;
  672.          end;
  673.       end;
  674.  
  675. invariant
  676.  
  677.    not type.is_anchored;
  678.  
  679.    type.start_position /= Void;
  680.  
  681. end -- PARENT
  682.  
  683.