--          This file is part of SmallEiffel The GNU Eiffel Compiler.
--          Copyright (C) 1994-98 LORIA - UHP - CRIN - INRIA - FRANCE
--            Dominique COLNET and Suzanne COLLIN - colnet@loria.fr
--                       http://SmallEiffel.loria.fr
-- SmallEiffel is  free  software;  you can  redistribute it and/or modify it
-- under the terms of the GNU General Public License as published by the Free
-- Software  Foundation;  either  version  2, or (at your option)  any  later
-- version. SmallEiffel is distributed in the hope that it will be useful,but
-- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-- or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU General Public License
-- for  more  details.  You  should  have  received a copy of the GNU General
-- Public  License  along  with  SmallEiffel;  see the file COPYING.  If not,
-- write to the  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-- Boston, MA 02111-1307, USA.
--
class CP_INFO
   --
   -- Print a human readable version of a JVM *.class generated
   -- by SmallEiffel.
   --

inherit CP_INFO_TAGS;

creation clear

feature {PRINT_JVM_CLASS}

   tag: CHARACTER; -- Must be one defined in CP_INFO_TAGS.

   info: STRING; -- Contains the corresponding information.

feature {CONSTANT_POOL}

   clear is
      do
         tag := Constant_empty;
         if info = Void then
            !!info.make(4);
         else
            info.clear;
         end;
      end;

   is_tagged(tag_value: CHARACTER): BOOLEAN is
      do
         Result := tag = tag_value;
      end;

feature

   set_class(i: STRING) is
      require
         i.count = 2
      do
         tag := Constant_class;
         info.copy(i);
      end;

   set_fieldref(i: STRING) is
      require
         i.count = 4
      do
         tag := Constant_fieldref;
         info.copy(i);
      end;

   set_methodref(i: STRING) is
      require
         i.count = 4
      do
         tag := Constant_methodref;
         info.copy(i);
      end;

   set_interface_methodref(i: STRING) is
      require
         i.count = 4
      do
         tag := Constant_interfacemethodref;
         info.copy(i);
      end;

   set_string(str: STRING) is
      require
         str.count >= 2
      local
         i: INTEGER;
         c: CHARACTER;
      do
         tag := Constant_string;
         info.clear;
         info.extend(str.item(1));
         info.extend(str.item(2));
         from
            i := 3;
         until
            i > str.count
         loop
            c := str.item(i);
            if c = '%U' then
               info.extend('%/192/');
               info.extend('%/128/');
            else
               info.extend(c);
            end;
            i := i + 1;
         end;
      end;

   set_integer(i: STRING) is
      require
         i.count = 4
      do
         tag := Constant_integer;
         info.copy(i);
      end;

   set_float(i: STRING) is
      require
         i.count = 4
      do
         tag := Constant_float;
         info.copy(i);
      end;

   set_long(i: STRING) is
      require
         i.count = 8
      do
         tag := Constant_long;
         info.copy(i);
      end;

   set_double(i: STRING) is
      require
         i.count = 8
      do
         tag := Constant_double;
         info.copy(i);
      end;

   set_name_and_type(i: STRING) is
      require
         i.count = 4
      do
         tag := Constant_name_and_type;
         info.copy(i);
      end;

   set_utf8(i: STRING) is
      require
         i.count >= 2
      do
         tag := Constant_utf8;
         info.copy(i);
      ensure
         info.count = u2_to_integer(1) + 2
      end;

feature -- Testing :

   is_class: BOOLEAN is
      do
         Result := tag = Constant_class;
      end;

   is_fieldref: BOOLEAN is
      do
         Result := tag = Constant_fieldref;
      end;

   is_methodref: BOOLEAN is
      do
         Result := tag = Constant_methodref;
      end;

   is_interface_methodref: BOOLEAN is
      do
         Result := tag = Constant_interfacemethodref;
      end;

   is_string: BOOLEAN is
      do
         Result := tag = Constant_string;
      end;

   is_integer: BOOLEAN is
      do
         Result := tag = Constant_integer;
      end;

   is_float: BOOLEAN is
      do
         Result := tag = Constant_float;
      end;

   is_long: BOOLEAN is
      do
         Result := tag = Constant_long;
      end;

   is_double: BOOLEAN is
      do
         Result := tag = Constant_double;
      end;

   is_name_and_type: BOOLEAN is
      do
         Result := tag = Constant_name_and_type;
      end;

   is_utf8: BOOLEAN is
      do
         Result := tag = Constant_utf8;
      end;

feature

   view_in(str: STRING) is
         -- Append in `str' a human readable version.
         -- Note: assume `constant_pool' is checked.
      local
         idx, length, i: INTEGER;
      do
         inspect
            tag
         when Constant_class then
            idx := u2_to_integer(1);
            constant_pool.view_in(str,idx);
         when Constant_fieldref then
            idx := u2_to_integer(1);
            constant_pool.view_in(str,idx);
            str.extend('.');
            idx := u2_to_integer(3);
            constant_pool.view_in(str,idx);
         when Constant_methodref then
            idx := u2_to_integer(1);
            constant_pool.view_in(str,idx);
            str.extend('.');
            idx := u2_to_integer(3);
            constant_pool.view_in(str,idx);
         when Constant_interfacemethodref then
         when Constant_string then
            idx := u2_to_integer(1);
            constant_pool.view_in(str,idx);
         when Constant_integer then
         when Constant_float then
         when Constant_long then
         when Constant_double then
         when Constant_name_and_type then
            idx := u2_to_integer(1);
            constant_pool.view_in(str,idx);
            str.extend(':');
            idx := u2_to_integer(3);
            constant_pool.view_in(str,idx);
         when Constant_utf8 then
            from
               length := u2_to_integer(1);
               i := 3;
            until
               length = 0
            loop
               str.extend(info.item(i));
               i := i + 1;
               length := length - 1;
            end;
         end;
      end;

feature {CONSTANT_POOL}

   b_put is
      do
         jvm.b_put_u1(tag)
         jvm.b_put_byte_string(info);
      end;

feature {CONSTANT_POOL} -- Update and search :
   -- *** ACOMPLETER AU FUR ET A MESURE ***

   is_class_idx(utf8: INTEGER): BOOLEAN is
      do
         if Constant_class = tag then
            Result := u2_to_integer(1) = utf8;
         end;
      end;

   is_fieldref_idx(c, nt: INTEGER): BOOLEAN is
      do
         if Constant_fieldref = tag then
            if u2_to_integer(1) = c then
               Result := u2_to_integer(3) = nt;
            end;
         end;
      end;

   is_methodref_idx(c, nt: INTEGER): BOOLEAN is
      do
         if Constant_methodref = tag then
            if u2_to_integer(1) = c then
               Result := u2_to_integer(3) = nt;
            end;
         end;
      end;

   is_name_and_type_idx(n, d: INTEGER): BOOLEAN is
      do
         if Constant_name_and_type = tag then
            if u2_to_integer(1) = n then
               Result := u2_to_integer(3) = d;
            end;
         end;
      end;

   is_string_idx(utf8: INTEGER): BOOLEAN is
      do
         if Constant_string = tag then
            Result := u2_to_integer(1) = utf8;
         end;
      end;

   is_utf8_idx(contents: STRING): BOOLEAN is
      local
         i1, i2: INTEGER;
      do
         if Constant_utf8 = tag then
            if u2_to_integer(1) = contents.count then
               from
                  i1 := contents.count + 1;
                  i2 := info.count + 1;
                  check
                     i1 + 2 = i2
                  end;
                  Result := true;
               until
                  not Result or else i1 = 1
               loop
                  i1 := i1 - 1;
                  i2 := i2 - 1;
                  Result := contents.item(i1) = info.item(i2);
               end;
            end;
         end;
      end;

feature {NONE}

   u2_to_integer(i: INTEGER): INTEGER is
      do
         Result := info.item(i).code * 256;
         Result := Result + info.item(i + 1).code;
      end;

end -- CP_INFO

