--          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 CODE_PRINTER
   --
   -- Common root for C_PRETTY_PRINTER and JVM.
   --

inherit GLOBALS;

feature

   output_name: STRING;
	 -- The executable name (Void means that "a.out" for 
	 -- C mode). For JVM mode, this name is used as the name of
	 -- the main output class file and as the name of the 
	 -- directory used to store auxilliary class files.
   
   set_output_name(name: STRING) is
      require
	 name /= Void
      do
	 if name.has_suffix(eiffel_suffix) then
	    eh.append("Bad executable name: %"");
	    eh.append(name);
	    fatal_error("%". Must not use Eiffel source file suffix %
			%with option %"-o <executable_name>%".");
	 end;
	 output_name := name;
      ensure
	 output_name = name;
	 not output_name.has_suffix(eiffel_suffix)
      end;

feature 
   
   incr_static_expression_count is
      do
	 static_expression_count := static_expression_count + 1;
      end;
   
feature {NONE}
   
   inlined_procedure_count: INTEGER;
   
   inlined_function_count: INTEGER;
   
   procedure_count: INTEGER;

   function_count: INTEGER;

   real_procedure_count: INTEGER;

   real_function_count: INTEGER;
   
   static_expression_count: INTEGER;

feature {RUN_FEATURE_3, RUN_FEATURE_10}
   
   incr_inlined_procedure_count is
      do
	 inlined_procedure_count := inlined_procedure_count + 1;
      end;
   
   incr_real_procedure_count is
      do
	 real_procedure_count := real_procedure_count + 1;
      end;
   
   incr_procedure_count is
      do
	 procedure_count := procedure_count + 1;
      end;
   
feature {RUN_FEATURE_4, RUN_FEATURE_11}
   
   incr_inlined_function_count is
      do
	 inlined_function_count := inlined_function_count + 1;
      end;
   
   incr_real_function_count is
      do
	 real_function_count := real_function_count + 1;
      end;
   
   incr_function_count is
      do
	 function_count := function_count + 1;
      end;
   
feature {RUN_FEATURE_6}
   
   add_pre_computed_once_function(rf6: RUN_FEATURE_6) is
      do
	 pre_computed_once.add_last(rf6);
      end;
   
feature {NONE}
   
   pre_computed_once: FIXED_ARRAY[RUN_FEATURE_6] is
      once
	 !!Result.with_capacity(32);
      end;

feature {NONE} -- Context stacks :
   
   top: INTEGER;
	 -- Index for top of followings stacks.
   
   stack_code: FIXED_ARRAY[INTEGER] is
	 -- The indicating stack. It contains only one 
	 -- of the following unique code.
      once
	 !!Result.make(stack_first_size);
      end;

   C_direct_call: INTEGER is unique;
	 -- Target is sure not to be Void and there is only one possible 
	 -- type (target is often Current, a manifest string or an expanded).
   
   C_check_id: INTEGER is unique; 
	 -- Target is a reference type which can be Void but only one type 
	 -- is the good one. 
   
   C_switch: INTEGER is unique;
	 -- Target is a reference type with more than one possibility. 
   
   C_inside_new: INTEGER is unique;
	 -- Target has been just created inside a creation call and 
	 -- need some initializing procedure call.
   
   C_expanded_initialize: INTEGER is unique;
	 -- Target is some expanded to initialize.
   
   C_inline_dca: INTEGER is unique;
	 -- Inlining of a direct call applied on attribute of target.
	 -- Target is the one given at `top-1' plus the access to 
	 -- the corresponding attribute stored at level `top'.
	 -- Arguments are taken at `top-1' context.

   C_same_target: INTEGER is unique;
	 -- Target is stored at level top - 1;

   C_inline_one_pc: INTEGER is unique;
	 -- Inlining `one_pc' of RUN_FEATURE_3;

   C_inside_twin: INTEGER is unique;
         -- In order to call the user's `copy'.

   C_precursor: INTEGER is unique;
	 -- For Precursor calls.

   -- Contents of stacks depends on `stack_code'.
   stack_rf: FIXED_ARRAY[RUN_FEATURE] is
      once
	 !!Result.make(stack_first_size);
      end;

   stack_target: FIXED_ARRAY[EXPRESSION] is
      once
	 !!Result.make(stack_first_size);
      end;

   stack_args: FIXED_ARRAY[EFFECTIVE_ARG_LIST] is
      once
	 !!Result.make(stack_first_size);
      end;

   stack_static_rf: FIXED_ARRAY[RUN_FEATURE] is
      once
	 !!Result.make(stack_first_size);
      end;

   stack_cpc: FIXED_ARRAY[CALL_PROC_CALL] is
      once
	 !!Result.make(stack_first_size);
      end;

   stack_first_size: INTEGER is 12;
   
   stack_push(code: INTEGER) is
	 -- Push the `code' and resize all stacks if needed.
      local
	 new_size: INTEGER;
      do
	 top := top + 1;
	 if top > stack_code.upper then
	    new_size := stack_code.upper * 2;
	    stack_code.resize(new_size);
	    stack_rf.resize(new_size);
	    stack_target.resize(new_size);
	    stack_args.resize(new_size);
	    stack_static_rf.resize(new_size);
	    stack_cpc.resize(new_size);
	    if new_size > 1024 then
	       stack_overflow
	    end;
	 end;
	 stack_code.put(code,top);
      end;

feature {E_PRECURSOR}

   push_precursor(rf: RUN_FEATURE; args: EFFECTIVE_ARG_LIST) is
      require
	 rf /= Void;
      do
	 stack_push(C_precursor);
	 stack_rf.put(rf,top);
	 stack_args.put(args,top);
	 direct_call_count := direct_call_count + 1;
      end;
   
feature {RUN_FEATURE_3}

   stack_not_full: BOOLEAN is
      do
	 Result := top < 50;
      end;

feature {NONE}
   
   stack_overflow is
      local
	 i: INTEGER;
	 rf: RUN_FEATURE;
	 rtm: STRING;
	 rtma: FIXED_ARRAY[STRING];
      do
	 eh.append("Infinite inlining loop (bad recursion ??). ");
	 from
	    i := top - 1;
	 until
	    i < stack_code.lower
	 loop
	    rf := stack_rf.item(i);
	    if rf /= Void then
	       eh.add_position(rf.start_position);
	       rtm := rf.current_type.run_time_mark;
	       if rtma = Void then
		  !!rtma.with_capacity(top);
		  rtma.add_last(rtm);
		  eh.append(rtm);
	       elseif rtma.fast_has(rtm) then
	       else
		  rtma.add_last(rtm);
		  eh.append(", ");
		  eh.append(rtm);
	       end;
	    end;
	    i := i - 1;
	 end;
	 eh.fatal_error(",...");
      end;
   
feature    
   
   pop is
      do
	 check
	    stack_code.lower <= top;
	 end;
	 top := top - 1;
      ensure
	 old(top) = top + 1
      end;
   
feature {NONE}
   
   check_id_count: INTEGER;
   
   direct_call_count: INTEGER;
   
   sure_void_count: INTEGER;
   
   switch_count: INTEGER;

feature {GC_HANDLER}

   incr_direct_call_count is
      do
	 direct_call_count := direct_call_count + 1;
      end;

   incr_switch_count is
      do
	 switch_count := switch_count + 1;
      end;

end -- CODE_PRINTER

