--          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://www.loria.fr/SmallEiffel
-- 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.
--
deferred class TYPE
--
-- Handling of an Eiffel type mark.
--
-- Handling of Eiffel kernel classes :
--   
--      Type Mark         |         Handle by Class
--      -------------------------------------------
--      BOOLEAN           |            TYPE_BOOLEAN 
--      CHARACTER         |          TYPE_CHARACTER 
--      INTEGER           |            TYPE_INTEGER 
--      REAL              |               TYPE_REAL 
--      DOUBLE            |             TYPE_DOUBLE 
--      POINTER           |            TYPE_POINTER
--      NONE              |               TYPE_NONE
--      ANY               |                TYPE_ANY
--      STRING            |             TYPE_STRING
--      ARRAY[FOO]        |              TYPE_ARRAY
--      NATIVE_ARRAY[BAR] |       TYPE_NATIVE_ARRAY
--      BIT 45            |              TYPE_BIT_1
--      BIT Foo           |              TYPE_BIT_2 
--   
-- Handling of other classes :
--
--      TYPE_CLASS : when original type mark is not generic, 
--            not outside expanded and it is not a formal 
--            generic argument. Thus, this is the most common 
--            case.
--
--      TYPE_FORMAL_GENERIC : when original declaration type mark
--            is a formal generic argument.
--
--      TYPE_LIKE_CURRENT : when written `like Current'
--
--      TYPE_LIKE_FEATURE : `like' <feature_name>
--
--      TYPE_LIKE_ARGUMENT : `like' <argument>
--
--      TYPE_EXPANDED : when original type is outside expanded (for
--            example when written   `foo : expanded BAR').
--
--      TYPE_GENERIC : when original type is generic, is not ARRAY,
--            not NATIVE_ARRAY and is not outside expanded.
--
--      TYPE_BIT_REF : corresponding reference type for TYPE_BIT.
--
--      TYPE_REF_TO_EXP : corresponding reference type for some 
--            expanded type.
--
   
inherit GLOBALS;
   
feature
   
   written_mark: STRING is
	 -- The original written type mark (what's in the source code).
      deferred
      ensure
	 Result = unique_string.item(Result)
      end;
   
   start_position: POSITION is
	 -- Of the written mark.
      deferred
      end;
   
   frozen written_in: CLASS_NAME is
      do
	 if start_position /= Void then
	    Result := start_position.base_class_name;
	 end;
      end;
      
   frozen pretty_print is
      do
	 fmt.put_string(written_mark);
      end;

   frozen short is
      do
	 short_print.hook("Btm");
	 short_hook;
	 short_print.hook("Atm");
      end;
   
   is_anchored: BOOLEAN is
	 -- Is it written "like ..." ?
      do
      end;
   
   is_like_current: BOOLEAN is
	 -- Is it written "like Current" ?
      deferred
      ensure
	 Result implies is_anchored
      end;
   
   is_like_feature: BOOLEAN is
	 -- Is it written "like <feature>" ?
      deferred
      ensure
	 Result implies is_anchored
      end;
   
   is_like_argument: BOOLEAN is
	 -- Is it written "like <argument>" ?
      deferred
      ensure
	 Result implies is_anchored
      end;
   
   is_generic: BOOLEAN is
	 -- Is the written type a generic type ?
      deferred
      ensure
	 is_array implies Result
      end;

   is_formal_generic: BOOLEAN is
	 -- Is it a formal generic argument ?
      do
      end;
	 
feature 
   
   is_run_type: BOOLEAN is
	 -- True when the running type is known (ie, when anchors 
	 -- are computed and when formal generic names are 
	 -- substitutes with real class names.
      deferred
      ensure
	 Result implies run_type /= Void
      end;
   
feature  -- Working with the run TYPE :
   
   run_type: TYPE is
	 -- Corresponding running type mark. 
      require
	 is_run_type
      deferred
      ensure
	 Result.run_type = Result
      end;
   
   is_expanded: BOOLEAN is
      require
	 is_run_type
      deferred
      ensure
	 Result implies not is_reference
      end;
   
   is_reference: BOOLEAN is
      require
	 is_run_type
      deferred
      ensure
	 Result implies not is_expanded
      end;
   
   like_feature: FEATURE_NAME is
      require
	 is_like_feature
      do
      ensure
	 Result /= Void
      end;
   
   generic_list: ARRAY[TYPE] is
	 -- Assume this is really a generic type, otherwise, print
	 -- a fatal error message with `fatal_error_generic_list'.
      deferred
      ensure
	 Result.lower = 1;
	 not Result.empty
      end;

   run_time_mark: STRING is
	 -- The corresponding type mark at execution time.
      require
	 is_run_type
      deferred
      ensure
	 Result = unique_string.item(Result)
      end;
   
   is_boolean: BOOLEAN is 
      require
	 is_run_type
      do 
      end;
   
   is_character: BOOLEAN is
      require
	 is_run_type
      do
      end;
   
   is_integer: BOOLEAN is
      require
	 is_run_type
      do
      end;
   
   is_real: BOOLEAN is
      require
	 is_run_type
      do
      end;
   
   is_double: BOOLEAN is
      require
	 is_run_type
      do
      end;

   is_string: BOOLEAN is
      require
	 is_run_type
      do
      end;
   
   is_array: BOOLEAN is
      require
	 is_run_type
      deferred
      ensure
	 Result implies generic_list.count = 1
      end;

   is_bit: BOOLEAN is
      require
	 is_run_type
      do
      end;

   is_any: BOOLEAN is
      require
	 is_run_type
      deferred
      end;
   
   is_none: BOOLEAN is
      require
	 is_run_type
      deferred
      end;
   
   is_pointer: BOOLEAN is
      require
	 is_run_type
      do
      end;
   
   is_basic_eiffel_expanded: BOOLEAN is
	 -- True for BOOLEAN, CHARACTER, INTEGER, REAL, DOUBLE
	 -- and POINTER. 
	 -- Note : all those type have the corresponding foo_REF 
	 -- class with the `item' attribute.
      require
	 is_run_type
      deferred
      end;

   frozen is_native_array: BOOLEAN is
      local
	 tna: TYPE_NATIVE_ARRAY;
      do
	 tna ?= Current;
	 Result := tna /= Void;
      end;

feature

   frozen convertible_to(other: TYPE): BOOLEAN is
      require
	 is_run_type;
	 other.is_run_type;
	 eh.empty
      do
	 if is_a(other) then
	    Result := true;
	 else
	    eh.cancel;
	    if other.is_a(Current) then
	       Result := true;
	    else
	       eh.cancel;
	    end;
	 end;
      ensure
	 eh.empty
      end;

feature  
   
   base_class_name: CLASS_NAME is
      require
	 is_run_type
      deferred
      ensure
	 Result /= Void
      end;
   
   to_runnable(ct: TYPE): like Current is
	 -- Compute the run time mark when the receiver is 
	 -- written in `ct'.  
	 -- Example : INTEGER always gives INTEGER. 
	 --           `like Current' gives `ct'.
	 --           ...
      require
	 ct.run_type = ct
      deferred
      ensure
	 no_errors implies written_mark = Result.written_mark;
	 no_errors implies start_position = Result.start_position;
	 no_errors implies Result.is_run_type;
	 no_errors implies Result.run_type = Result.run_type.run_type
      end;
   
   frozen base_class: BASE_CLASS is
      local
	 bcn: CLASS_NAME;
      do
	 bcn := base_class_name;
	 if bcn /= Void then
	    Result := bcn.base_class;
	 else
	    eh.append("Cannot find Base Class for ");
	    eh.add_type(Current,fz_dot);
	    eh.print_as_fatal_error;
	 end;
      end;
   
   frozen path: STRING is
      -- Of the corresponding `base_class'.
      do
	 Result := base_class.path;
      end;
   
feature
   
   is_a(other: TYPE): BOOLEAN is
	 -- Type conformance checking : Is it a kind of `other' ?
	 -- Assume that the context is identical.
	 --
	 -- When false, `eh' is filled if needed with the corresponding 
	 -- bad types, but the error report is not printed for the caller 
	 -- to add some comments or for the caller to cancel `eh'.
	 --
      require
	 is_run_type;
	 other.is_run_type
      deferred
      ensure
	 nb_errors = old nb_errors;
	 (not Result) implies (not eh.empty)
      end;
   
   frozen is_a_in(other: TYPE; rc: RUN_CLASS): BOOLEAN is
	 -- Is the written type mark `other' interpreted in `rc' 
	 -- is a kind of Current written type mark interpreted in `rc' ?
      require
	 other /= Void;
	 rc /= Void
      local
	 t1, t2, ct: TYPE;
      do
	 if written_mark = other.written_mark then
	    Result := true;
	 else
	    ct := rc.current_type;
	    t1 := to_runnable(ct); -- ** Memory LEAKS 
	    t2 := other.to_runnable(ct); -- ** Memory LEAKS 
	    if t1.run_time_mark = t2.run_time_mark then
	       Result := true;
	    else
	       Result := t1.is_a(t2);
	    end;
	 end;
      ensure
	 (not Result) implies (not eh.empty)
      end;
      
   has_creation(fn: FEATURE_NAME): BOOLEAN is
	 -- Is `fn' the name of procedure of creation.
      require
	 fn.start_position /= Void;
	 is_run_type
      deferred
      end;
   
   smallest_ancestor(other: TYPE): TYPE is
	 -- Return the smallest common ancestor.
      require
	 is_run_type;
	 other.is_run_type
      deferred
      ensure
	 Result.run_type = Result;
	 Current.is_a(Result);
	 other.is_a(Result)
      end;
   
   run_class: RUN_CLASS is
      require
	 is_run_type
      deferred
      ensure
	 Result /= Void
      end;
   
   frozen at_run_time: BOOLEAN is
      require
	 is_run_type
      do
	 Result := run_type.run_class.at_run_time;
      end;

   expanded_initializer: RUN_FEATURE_3 is
	 -- Non Void when it is an `is_user_expanded' with a user
	 -- creation procedure.
      require
	 is_run_type
      deferred
      end;
   
feature 

   c_header_pass1 is
      require
	 cpp.on_h;
	 run_class.at_run_time
      deferred
      ensure
	 cpp.on_h
      end;

   c_header_pass2 is
      require
	 cpp.on_h;
	 run_class.at_run_time
      deferred
      ensure
	 cpp.on_h
      end;

   c_header_pass3 is
      require
	 cpp.on_h;
	 run_class.at_run_time
      deferred
      ensure
	 cpp.on_h
      end;

   c_header_pass4 is
      require
	 cpp.on_h;
	 run_class.at_run_time
      deferred
      ensure
	 cpp.on_h
      end;

feature {NONE}

   frozen standard_c_typedef is
      require
	 cpp.on_h;
	 run_class.at_run_time
      local 
	 mem_id: INTEGER;
      do
	 mem_id := id;
	 tmp_string.clear;
	 if need_c_struct then
	    tmp_string.append(fz_typedef);
	    tmp_string.append(fz_struct);
	    tmp_string.extend('S');
	    mem_id.append_in(tmp_string);
	    tmp_string.extend(' ');
	    tmp_string.extend('T');
	    mem_id.append_in(tmp_string);
	    tmp_string.append(fz_00);
	 elseif is_dummy_expanded then
	    tmp_string.append(fz_typedef);
	    tmp_string.append(fz_int);
	    tmp_string.extend(' ');
	    tmp_string.extend('T');
	    mem_id.append_in(tmp_string);
	    tmp_string.append(fz_00);
	 elseif is_reference then
	    tmp_string.append(fz_typedef);
	    tmp_string.append(fz_void);
	    tmp_string.extend('*');
	    tmp_string.extend('T');
	    mem_id.append_in(tmp_string);
	    tmp_string.append(fz_00);
	 end;
	 cpp.put_string(tmp_string);
      ensure
	 cpp.on_h
      end;

feature {NONE}
   
   frozen standard_c_struct is
	 -- Produce C code for the standard C struct (for user's
	 -- expanded or reference as well).
      require
	 run_type = Current;
	 need_c_struct;
	 cpp.on_h
      local
	 wa: ARRAY[RUN_FEATURE_2];
	 i, mem_id: INTEGER;
	 a: RUN_FEATURE_2;
	 t: TYPE;
      do
	 mem_id := id;
	 wa := run_class.writable_attributes;
	 tmp_string.copy(fz_struct);
	 tmp_string.extend('S');
	 mem_id.append_in(tmp_string);
	 tmp_string.extend('{');
	 if is_reference then
	    if run_class.is_tagged then
	       tmp_string.append("int id;");
	    end;
	 end;
	 if wa /= Void then
	    from
	       i := wa.upper;
	    until
	       i = 0
	    loop
	       a := wa.item(i);
	       t := a.result_type.run_type;
	       t.c_type_for_result_in(tmp_string);
	       tmp_string.extend(' ');
	       tmp_string.extend('_');
	       tmp_string.append(a.name.to_string);
	       tmp_string.extend(';');
	       i := i - 1;
	    end;
	 end;
	 tmp_string.extend('}');
	 tmp_string.append(fz_00);
	 cpp.put_string(tmp_string);
	 if is_expanded then
	    -- For expanded comparison :
	    tmp_string.copy(fz_int);
	    tmp_string.extend(' ');
	    tmp_string.append(fz_se_cmpt);
	    mem_id.append_in(tmp_string);
	    tmp_string.append("(T");
	    mem_id.append_in(tmp_string);
	    tmp_string.append(" o1,T");
	    mem_id.append_in(tmp_string);
	    tmp_string.append(" o2)");
	    cpp.put_c_function(tmp_string,
	    "return memcmp(&o1,&o2,sizeof(o1));");
	 end;
      ensure	 
	 cpp.on_h
      end;

   frozen standard_c_object_model is
	 -- Produce C code to define the model object.
      require
	 run_type = Current;
	 cpp.on_h
      local
	 mem_id: INTEGER;
	 rc: RUN_CLASS;
      do
	 rc := run_class;
	 mem_id := rc.id;
	 tmp_string.clear;
	 tmp_string.extend('T');
	 mem_id.append_in(tmp_string);
	 tmp_string.extend(' ');
	 tmp_string.extend('M');
	 mem_id.append_in(tmp_string);
	 cpp.put_extern7(tmp_string);
	 cpp.swap_on_c;
	 tmp_string.clear;
	 rc.c_object_model_in(tmp_string);
	 tmp_string.append(fz_00);
	 cpp.put_string(tmp_string);
	 cpp.swap_on_h;
      ensure	 
	 cpp.on_h
      end;

   frozen standard_c_print_function is
	 -- Produce `prinTid' function.
      require
	 run_type = Current;
      do
	 if run_control.no_check then
	    run_class.c_print_function;
	 end;
      end;

feature
      
   id: INTEGER is
	 -- All `at_run_time' has a Tid C type.
      require
	 is_run_type
      deferred
      ensure
	 Result > 0
      end;

   is_dummy_expanded: BOOLEAN is
	 -- True when is it a user's expanded type with no attribute.
      require
	 is_run_type;
	 small_eiffel.is_ready
      deferred
      end;

   is_user_expanded: BOOLEAN is
	 -- Is it really a user expanded type ?
      require
	 is_run_type
      deferred
      end;

   c_type_for_argument_in(str: STRING) is
	 -- Append in `str' the C type to use when current 
	 -- Eiffel type is used for an argument of a feature.
      require
	 small_eiffel.is_ready;
	 str /= Void
      deferred
      end;

   c_type_for_target_in(str: STRING) is
	 -- Append in `str' the C type to use when current 
	 -- Eiffel type is used for an argument of a feature.
      require
	 small_eiffel.is_ready;
	 str /= Void
      deferred
      end;

   c_type_for_result_in(str: STRING) is
	 -- Append in `str' the C type to use when current Eiffel 
	 -- type is used as a result type of a C function.
      require
	 small_eiffel.is_ready;
	 str /= Void
      deferred
      end;

   frozen c_type_for_external_in(str: STRING) is
      do
	 if is_reference then
	    str.append(fz_void);
	    str.extend('*');
	 else
	    c_type_for_result_in(str);
	 end;
      end;

   frozen mapping_cast is
	 -- Produce a C cast for conversion into current C type.
      require
	 is_run_type;
	 run_type.run_class.at_run_time
      do
         mapping_cast_memory.clear;
	 mapping_cast_memory.extend('(');
	 c_type_for_target_in(mapping_cast_memory);
	 mapping_cast_memory.extend(')');
	 cpp.put_string(mapping_cast_memory);
      end;

feature {NONE}

   mapping_cast_memory: STRING is "................";

feature
   
   cast_to_ref is
	 -- Produce the good C cast to use INTEGER_REF, BOOLEAN_REF,
	 -- CHARACTER_REF, REAL_REF or DOUBLE_REF.
      require
	 is_run_type;
	 is_basic_eiffel_expanded
      do
	 run_type.cast_to_ref;
      end;
   
   used_as_reference is
	 -- Do what's to be done when current type may be cast into
	 -- a reference type.
      deferred
      end;
   
   to_reference is
	 -- Print the C name of the automatic conversion function. 
      deferred
      end;
   
   to_expanded is
	 -- Print the C name of the automatic conversion function. 
      do
      end;

   need_c_struct: BOOLEAN is
	 -- Is it necessary to define a C struct ?
      require
	 small_eiffel.is_ready
      deferred
      end;

   space_for_variable: INTEGER is
	 -- In number of bytes.
      require
	 is_run_type
      deferred
      ensure
	 Result >= 1
      end;

   space_for_object: INTEGER is
	 -- In number of bytes.
      require
	 is_run_type
      deferred
      ensure
	 Result >= 0
      end;

   c_initialize is
	 -- Produce C code for initialisation of local variables
	 -- or attributes.
      require
	 is_run_type;
	 small_eiffel.is_ready
      deferred
      end;

   c_initialize_in(str: STRING) is
	 -- In order to initialize local variables or attributes
	 -- with the default simple value (0, NULL, 0.0, etc.).
      require
	 is_run_type;
	 small_eiffel.is_ready
      deferred
      end;

   frozen c_frame_descriptor is
      do
	 c_frame_descriptor_format.extend('%%');
	 if is_reference then
	    c_frame_descriptor_format.extend('R');
	 else
	    c_frame_descriptor_format.extend('E');
	 end;
	 id.append_in(c_frame_descriptor_format);
	 c_frame_descriptor_format.extend('%%');
      end;

feature {NONE}

   frozen space_for_pointer: INTEGER is
      require
	 is_run_type
      local
	 p: POINTER;
      do
	 Result := p.object_size;
      end;

   frozen space_for_integer: INTEGER is
      require
	 is_run_type
      do
	 Result := (1).object_size;
      end;

   frozen standard_space_for_object: INTEGER is
	 -- In number of bytes.
      require
	 is_run_type
      local
	 rc: RUN_CLASS;
	 wa: ARRAY[RUN_FEATURE_2];
	 a: RUN_FEATURE_2;
	 i: INTEGER;
      do
	 rc := run_class;
	 if rc.is_tagged then
	    Result := space_for_integer;
	 end;
	 wa := rc.writable_attributes;
	 if wa /= Void then
	    from
	       i := wa.upper;
	    until
	       i = 0
	    loop
	       a := wa.item(i);
	       Result := Result + a.result_type.space_for_variable;
	       i := i - 1;
	    end;
	 end;
	 if Result = 0 then
	    Result := space_for_integer;
	 end;
      end;

feature 

   need_gc_mark_function: BOOLEAN is
	 -- True when objects of the current type must be marked
	 -- or when `gc_mark_to_follow' is true in corresponding run 
	 -- class.
      deferred
      end;
   
feature {RUN_CLASS,TYPE}

   gc_define1 is
	 -- Define prototypes and C struct for the Garbage Collector
      require
	 not gc_handler.is_off;
	 cpp.on_h;
	 run_class.at_run_time
      deferred
      end;

   gc_define2 is
	 -- Define C functions for the Garbage Collector
      require
	 not gc_handler.is_off;
	 cpp.on_c;
	 run_class.at_run_time
      deferred
      end;

   gc_info_in(str: STRING) is
	 -- Produce C code to print GC information.
      require
	 not gc_handler.is_off;
	 gc_handler.info_flag;
	 run_class.at_run_time
      deferred
      end;

   just_before_gc_mark_in(str: STRING) is
      require
	 not gc_handler.is_off;
	 run_class.at_run_time
      deferred
      end;

feature {NONE}

   standard_just_before_gc_mark_in(str: STRING) is
      require
	 not gc_handler.is_off;
	 run_class.at_run_time
      do
	 gc_free_in(str);
	 str.extend('=');
	 str.append(fz_null);
	 str.append(fz_00);
      end;

feature {NATIVE_SMALL_EIFFEL,GC_HANDLER}

   gc_call_new_in(str: STRING) is
      do
	 str.append(fz_new);
	 id.append_in(str);
	 str.extend('(');
	 str.extend(')');
      end;
   
feature

   jvm_method_flags: INTEGER is
	 -- Return the appropriate flag (static/virtual) when the
	 -- receiver has this type.
      deferred
      end;

   frozen jvm_stack_space: INTEGER is
      require
	 is_run_type
      do
	 if is_double then
	    Result := 2;
	 else
	    Result := 1;
	 end;
      ensure
	 Result >= 1
      end;

   jvm_descriptor_in(str: STRING) is
	 -- Append in `str' the appropriate JVM type descriptor for
	 -- arguments and Result of a method.
      require
	 str /= Void
      deferred
      end;

   jvm_target_descriptor_in(str: STRING) is
	 -- Append in `str' the appropriate JVM type descriptor for
	 -- the target only.
      require
	 str /= Void;
	 run_class.at_run_time
      deferred
      end;

   jvm_return_code is
	 -- Add the good JVM opcode to return Result. 
      require
	 run_type = Current
      deferred
      end;

   jvm_push_local(offset: INTEGER) is
	 -- Push value of the local variable at `offset'.
      deferred
      end;

   jvm_push_default: INTEGER is
	 -- Push the default value for the Current type.
	 -- Result gives the space in the JVM stack;
      deferred
      end;

   jvm_initialize_local(offset: INTEGER) is
	 -- Initialize the local variable at `offset'.
      deferred
      end;

   jvm_write_local(offset: INTEGER) is
	 -- Write the local variable at `offset' using the stack top.
      deferred
      end;

   jvm_check_class_invariant is
	 -- If needed, add some byte code to check the class invariant 
	 -- of the pushed object.
      deferred
      end;

   jvm_xnewarray is
	 -- Produce the appropriate byte-code to create a new JVM 
	 -- array with elements of `Current' type.
	 -- Assume the count of the new array to create is already
	 -- pushed.
      deferred
      end;

   jvm_xastore is
      deferred
      end;

   jvm_xaload is
      deferred
      end;

   jvm_if_x_eq: INTEGER is
	 -- Assume two operands of the same type are pushed.
      deferred
      end;

   jvm_if_x_ne: INTEGER is
	 -- Assume two operands of the same type are pushed.
      deferred
      end;

   jvm_convert_to(destination: TYPE): INTEGER is
	 -- Convert the pushed value (which is an object of 
	 -- the current type) into an object of `destination' type. 
      require
	 convertible_to(destination)
      deferred
      ensure
	 Result >= 1
      end;

   jvm_standard_is_equal is
	 -- Produce byte-code for `standard_is_equal' for the 
	 -- top objects pair.
      deferred
      end;

feature {NONE} 

   frozen standard_jvm_check_class_invariant is
      do
	 if run_control.invariant_check then
	    run_class.jvm_check_class_invariant;
	 end;
      end;

feature {TYPE}
   
   jvm_to_reference is
	 -- If needed, convert the pushed value into the 
	 -- corresponding reference type.
      deferred
      end;

   jvm_expanded_from_reference(other: TYPE): INTEGER is
	 -- Convert the pushed value of type `other' which is a reference 
	 -- type into the corresponding expanded type.
      require
	 is_expanded;
	 other.is_reference;
	 is_a(other)
      deferred
      ensure
	 Result >= 1
      end;

feature {NONE} 
   
   c_initialize_expanded is
      require
	 is_user_expanded or is_dummy_expanded
      local
	 wa: ARRAY[RUN_FEATURE_2];
	 i: INTEGER;
	 rf: RUN_FEATURE_2;
      do
	 if is_dummy_expanded then
	    cpp.put_character('0');
	 else
	    cpp.put_character('{');
	    wa := run_class.writable_attributes;
	    from  
	       i := wa.upper;
	    until
	       i = 0
	    loop
	       rf := wa.item(i);
	       rf.result_type.c_initialize;
	       i := i - 1;
	       if i > 0 then
		  cpp.put_character(',');
	       end;
	    end;
	    cpp.put_character('}');
	 end;
      end;

feature {PARENT,TYPE}
      
   frozen look_up_for(rc: RUN_CLASS; fn: FEATURE_NAME): E_FEATURE is
      -- Look for the good one to compute `rc' X `fn'.
      require
	 rc /= Void;
	 fn /= Void;
	 not is_anchored;
	 not is_formal_generic;
      do
	 Result := base_class.look_up_for(rc,fn);
      end;
   
feature {RUN_CLASS}

   frozen demangling_in(str: STRING) is
      do 
	 if is_reference then
	    str.extend('R');
	 else 
	    str.extend('E');
	 end;
	 str.extend(' ');
	 str.append(run_time_mark);
      end;

feature {NONE}

   tmp_string: STRING is "................................................................%
                         %................................................................";

   header: STRING is "................................................................%
                     %................................................................";

   body: STRING is "................................................................%
                   %................................................................%
                   %................................................................%
                   %................................................................";

feature {TYPE}

   short_hook is
      deferred
      end;

feature {NONE}

   fatal_error_generic_list is
      do
	 check
	    not is_generic; 
	 end;
	 eh.add_type(Current," is (not) generic ?");
	 eh.print_as_fatal_error;
      end;

feature {NONE}

   frozen standard_gc_info_in(str: STRING) is
      do
	 -- Print gc_info_nbXXX :
	 str.append(fz_printf);
	 str.extend('(');
	 str.extend('%"');
	 str.append(run_time_mark);
	 str.append(fz_10);
	 gc_info_nb_in(str);
	 str.append(fz_14);
	 -- Print store_leftXXX :
	 str.append(fz_printf);
	 str.extend('(');
	 str.extend('%"');
	 gc_store_left_in(str);
	 str.append(fz_10);
	 gc_store_left_in(str);
	 str.append(fz_14);
      end;

   frozen standard_gc_define1 is
	 -- For Fixed Size Objects.
      require
	 not gc_handler.is_off;
	 cpp.on_h;
	 run_class.at_run_time
      local
	 rc: RUN_CLASS;
	 rcid: INTEGER;
      do
	 rc := run_class;
	 rcid := rc.id;
	 -- --------------- Define struct BXXX and typedef gcXXX :
	 header.copy(fz_typedef);
	 header.append(fz_struct);
	 header.extend('B');
	 rcid.append_in(header);
	 header.extend(' ');
	 header.append(fz_gc);
	 rcid.append_in(header);
	 header.append(fz_00);
	 header.append(fz_struct);
	 header.extend('B');
	 rcid.append_in(header);
	 header.append("{T");
	 rcid.append_in(header);
	 header.append(" object;union {int flag;gc");
	 rcid.append_in(header);
	 header.append("*next;} header;};%N");
	 cpp.put_string(header);
	 -- ----------------------------------- Declare storeXXX :
	 header.copy(fz_gc);
	 rcid.append_in(header);
	 header.extend('*');
	 gc_store_in(header);
	 cpp.put_extern5(header,fz_null);
	 -- ------------------------------ Declare store_leftXXX :
	 header.copy(fz_int);
	 header.extend(' ');
	 gc_store_left_in(header);
	 cpp.put_extern2(header,'0');
	 -- ----------------------------------- Declare store_chunkXXX :
	 header.copy("fsoc*");
	 gc_store_chunk_in(header);
	 cpp.put_extern5(header,fz_null);
	 -- --------------------------------- Declare gc_freeXXX :
	 header.copy(fz_gc);
	 rcid.append_in(header);
	 header.extend('*');
	 gc_free_in(header);
	 cpp.put_extern5(header,fz_null);
	 -- -------------------------------- Declare gc_info_nbXXX :
	 if gc_handler.info_flag then
	    header.copy(fz_int);
	    header.extend(' ');
	    gc_info_nb_in(header);
	    cpp.put_extern2(header,'0');
	 end;
      end;

   frozen standard_gc_define2 is
      require
	 is_reference;
	 not gc_handler.is_off;
	 cpp.on_c;
	 run_class.at_run_time
      local
	 rc: RUN_CLASS;
	 rcid: INTEGER;
	 gc_check_id: BOOLEAN;
      do
	 rc := run_class;
	 rcid := rc.id;
	 -- --------------------------- Definiton for gc_sweepXXX :
	 header.copy(fz_void);
	 header.extend(' ');
	 header.append(fz_gc_sweep);
	 rcid.append_in(header);
	 header.append("(fsoc*c)");
	 body.copy("gc");
	 rcid.append_in(body);
	 body.append(
            "*o1,*o2,*flt,flh;%N%
	    %o1=((void*)(&(c->first_object)));%N%
	    %if(c->header.state_type==FSO_STORE_CHUNK){%N%
	    %for(;o1<");
         gc_store_in(body);
	 body.append(
            ";o1++){%N%
            %if((o1->header.flag)==FSOH_MARKED){%N%
	    %o1->header.flag=FSOH_UNMARKED;%N}%N%
	    %else{%N%
	    %o1->header.next=");
	 gc_free_in(body);
	 body.append(fz_00);
	 gc_free_in(body);
	 body.append(
            "=o1;%N}%N}%N}%N%
	    %else{%N%
	    %int dead=1;%N%
	    %flh.header.next=NULL;%N%
	    %flt=&flh;%N%
	    %o2=o1+c->count_minus_one;%N%
            %for(;o1<=o2;o2--){%N%
            %if((o2->header.flag)==FSOH_MARKED){%N%
	    %o2->header.flag=FSOH_UNMARKED;%N%
	    %dead=0;}%N%
	    %else{%N%
	    %flt->header.next=o2;%N%
	    %flt=o2;%N%
	    %}%N}%N%
	    %if (dead){%N%
	    %c->next=fsocfl;%N%
	    %fsocfl=c;%N%
	    %c->header.state_type=FSO_FREE_CHUNK;%N%N}%N%
	    %else if(flh.header.next!=NULL){%N%
	    %flt->header.next=");
	 gc_free_in(body);
	 body.append(fz_00);
	 gc_free_in(body);
	 body.append(
            "=flh.header.next;%N%
	    %}%N}%N");
	 cpp.put_c_function(header,body);
	 -- ----------------------------- Definiton for gc_markXXX :
	 header.copy(fz_void);
	 header.extend(' ');
	 gc_mark_in(header);
	 header.append("(T");
	 rcid.append_in(header);
	 header.append("*o)");
	 body.clear;
	 gc_check_id := rc.is_tagged and then run_control.no_check;
	 if gc_check_id then
	    body.append("se_gc_check_id(o,");
	    rcid.append_in(body);
            body.append(");%N{");
	 end;
	 rc.gc_mark_fixed_size(false,body);
	 if gc_check_id then
	    body.append("%N}");
	 end;
	 cpp.put_c_function(header,body);
	 -- ----------------------- Definiton for gc_align_markXXX :
	 header.copy(fz_void);
	 header.extend(' ');
	 gc_align_mark_in(header);
	 header.append("(fsoc*c,gc");
	 rcid.append_in(header);
	 header.append("*p)");
	 body.clear;
	 rc.gc_align_mark_fixed_size(body);
	 cpp.put_c_function(header,body);
	 -- ------------------------ Definiton of chunk model HXXX :
	 header.copy("fsoc H");
	 rcid.append_in(header);
	 body.copy(
            "{{FSOC_SIZE,FSO_STORE_CHUNK,%N%
            %(void(*)(mch*,void*))gc_align_mark");
	 rcid.append_in(body);
         body.append(
            ",%N%
            %(void(*)(mch*))gc_sweep");
	 rcid.append_in(body);
         body.append(
            "},NULL,((FSOC_SIZE-sizeof(fsoc)+sizeof(double))/sizeof(gc");
	 rcid.append_in(body);
         body.append("))-1}");
         cpp.put_extern5(header,body);
	 -- --------------------------------- Definiton for newXXX :
	 header.clear;
	 header.extend('T');
	 rcid.append_in(header);
	 header.extend('*');
	 header.append(fz_new);
	 rcid.append_in(header);
	 header.append(fz_c_void_args);
	 body.copy(fz_gc);
	 rcid.append_in(body);
	 body.append("*n;%N");
	 if gc_handler.info_flag then
            gc_info_nb_in(body);
            body.append("++;%N");
         end;
         --
         body.append("if(");
         gc_store_left_in(body);
         body.append(">1){%N")
         gc_store_left_in(body);
         body.append("--;%Nn=");
         gc_store_in(body);
         body.append("++;%N}%N%
		     %else if (");
         gc_free_in(body);
         body.append("!=NULL){%N%
		     %n=");
         gc_free_in(body);
         body.append(fz_00);
         gc_free_in(body);
         body.append("=n->header.next;%N}%N%
		     %else if(");
	 gc_store_left_in(body);
         body.append("==1){%N");
         gc_store_left_in(body);
         body.append("=0;%N");
         gc_store_chunk_in(body);
         body.append("->header.state_type=FSO_USED_CHUNK;%N%
		     %n=");
         gc_store_in(body);
         body.append("++;%N}%N%
		     %else if(");
         body.append("fsocfl!=NULL) {%N");
	 gc_store_chunk_in(body);
         body.append("=fsocfl;%N%
		     %fsocfl=fsocfl->next;%N%
		     %*");
	 gc_store_chunk_in(body);
         body.append(fz_eq_h);
	 rcid.append_in(body);
         body.append(fz_00);
         gc_store_in(body);
         body.append("=(void*)(&(");
	 gc_store_chunk_in(body);
         body.append("->first_object));%N");
         gc_store_left_in(body);
         body.append(fz_eq_h);
	 rcid.append_in(body);
         body.append(".count_minus_one;%N%
		     %n=");
         gc_store_in(body);
         body.append("++;%N}%N%
		     %else if(fsoc_count_ceil>fsoc_count) {%N");
	 gc_store_chunk_in(body);
         body.append("=malloc(FSOC_SIZE);%N%
		     %fsoc_count++;%N%
		     %{mch**p;%N%
		     %if(gcmt_used==gcmt_max){%N%
		     %gcmt_max<<=1;%N%
		     %gcmt=realloc(gcmt,(gcmt_max+1)*sizeof(void*));%N}%N%
		     %for(p=gcmt+(gcmt_used++ -1);(p>=gcmt)&&(*p>((mch*)");
	 gc_store_chunk_in(body);
         body.append("));p--)%N%
		     %*(p+1)=*p;%N%
		     %*(p+1)=(mch*)");
	 gc_store_chunk_in(body);
         body.append(";%N}%N%
		     %*");
	 gc_store_chunk_in(body);
         body.append(fz_eq_h);
	 rcid.append_in(body);
         body.append(fz_00);
         gc_store_in(body);
         body.append("=(void*)(&(");
	 gc_store_chunk_in(body);
         body.append("->first_object));%N");
         gc_store_left_in(body);
         body.append(fz_eq_h);
	 rcid.append_in(body);
         body.append(".count_minus_one;%N%
		     %n=");
         gc_store_in(body);
         body.append("++;%N}%Nelse{%N%
		     %gc_start();%N%
		     %if(NULL!=");
         gc_free_in(body);
         body.append("){%N%
		     %n=");
         gc_free_in(body);
         body.append(fz_00);
         gc_free_in(body);
         body.append("=n->header.next;%N}%Nelse{%N");
	 gc_store_chunk_in(body);
         body.append("=new_fsoc();%N%
		     %*");
	 gc_store_chunk_in(body);
         body.append(fz_eq_h);
	 rcid.append_in(body);
         body.append(fz_00);
         gc_store_in(body);
         body.append("=(void*)(&(");
	 gc_store_chunk_in(body);
         body.append("->first_object));%N");
         gc_store_left_in(body);
         body.append(fz_eq_h);
	 rcid.append_in(body);
         body.append(".count_minus_one;%N%
		     %n=");
         gc_store_in(body);
         body.append("++;%N}%N}%N%
		     %n->header.flag=FSOH_UNMARKED;%N");
	 if need_c_struct then
	    body.append("n->object=M");
	    rcid.append_in(body);
	    body.append(fz_00);
	 end;
         body.append("return (void*)n;%N");
	 cpp.put_c_function(header,body);
      end;

   frozen standard_gc_define2_for_expanded is
	 -- For user's expanded with reference attribute to mark.
      require
	 is_expanded;
	 not gc_handler.is_off;
	 cpp.on_c;
	 run_class.at_run_time
      local
	 rc: RUN_CLASS;
	 rcid: INTEGER;
      do
	 rc := run_class;
	 if rc.gc_mark_to_follow then
	    rcid := rc.id;
	    -- -------------------------- Definiton for gc_markXXX :
	    header.copy(fz_void);
	    header.extend(' ');
	    gc_mark_in(header);
	    header.append("(T");
	    rcid.append_in(header);
	    header.append("*o)");
	    body.clear;
	    rc.gc_mark_fixed_size(true,body);
	    cpp.put_c_function(header,body);
	 end;
      end;

   frozen gc_store_in(str: STRING) is
      do
	 str.append("store");
	 id.append_in(str);
      end;

   frozen gc_store_left_in(str: STRING) is
      do
	 str.append("store_left");
	 id.append_in(str);
      end;

   frozen gc_store_chunk_in(str: STRING) is
      do
	 str.append("store_chunk");
	 id.append_in(str);
      end;

   frozen gc_free_in(str: STRING) is
      do
	 str.append("gc_free");
	 id.append_in(str);
      end;

   frozen gc_align_mark_in(str: STRING) is
      do
	 str.append("gc_align_mark");
	 id.append_in(str);
      end;

   frozen gc_info_nb_in(str: STRING) is
      do
	 str.append("gc_info_nb");
	 id.append_in(str);
      end;

feature {TYPE, GC_HANDLER}

   frozen gc_mark_in(str: STRING) is
      do
	 str.append(fz_gc_mark);
	 id.append_in(str);
      end;

invariant
   
   written_mark = unique_string.item(written_mark)
   
end -- TYPE
