--          This file is part of SmartEiffel The GNU Eiffel Compiler.
--       Copyright (C) 1994-2002 LORIA - INRIA - U.H.P. Nancy 1 - FRANCE
--          Dominique COLNET and Suzanne COLLIN - SmartEiffel@loria.fr
--                       http://SmartEiffel.loria.fr
-- SmartEiffel 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. SmartEiffel 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  SmartEiffel;  see the file COPYING.  If not,
-- write to the  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-- Boston, MA 02111-1307, USA.
--
class CECIL_POOL
   --
   -- Unique global object in charge of CECIL calls.
   --

inherit GLOBALS

feature {ACE, COMMAND_LINE_TOOLS}

   add_file(path: STRING) is
	 -- Add `path' as a new -cecil file to be considered.
      require
	 path /= Void
      local
	 cecil_file: CECIL_FILE
      do
	 create cecil_file.make(path)
	 if cecil_files = Void then
	    create cecil_files.with_capacity(4)
	 end
	 cecil_files.add_last(cecil_file)
      end

feature {SMART_EIFFEL}

   fill_up is
      local
	 i: INTEGER
      do
	 if cecil_files /= Void then
	    from
	       i := cecil_files.upper
	    until
	       i < cecil_files.lower
	    loop
	       cecil_files.item(i).parse
	       i := i - 1
	    end
	 end
      end

   afd_check is
      local
	 i: INTEGER
      do
	 if cecil_files /= Void then
	    from
	       i := cecil_files.upper
	    until
	       i < cecil_files.lower
	    loop
	       cecil_files.item(i).afd_check
	       i := i - 1
	    end
	 end
      end

feature {C_PRETTY_PRINTER}

   c_define_users is
      local
	 i: INTEGER
      do
	 if cecil_files /= Void then
	    from
	       i := cecil_files.upper
	    until
	       i < cecil_files.lower
	    loop
	       cecil_files.item(i).c_define_users
	       i := i - 1
	    end
	 end
      end

feature {RUN_FEATURE}

   define_body_of(rf: RUN_FEATURE) is
      local
         rfct, rfrt: E_TYPE; face_target: FACE_TARGET
	 eal: EFFECTIVE_ARG_LIST; run_time_set: RUN_TIME_SET
      do
         rfct := rf.current_type
         rfrt := rf.result_type
         run_time_set := rfct.run_class.run_time_set
         if run_time_set.count = 0 then
            error_handler.add_type(rfct,
                                   once " not created (type is not alive).")
            error_handler.append(once " Empty Cecil/Wrapper function ")
            error_handler.append(rfct.run_time_mark)
            error_handler.append(rf.name.to_key)
            error_handler.extend('.')
            error_handler.print_as_warning
         else
            if ace.no_check then
               cpp.put_string(once "se_dump_stack ds={NULL,NULL,0,NULL,NULL};%N")
               if smart_eiffel.scoop then
                  --*** TO BE FIXED (`self' not defined)
                  cpp.put_string(once "(void)(self->vft.get_dst_and_lock(self));%N%
                                      %self->vft.set_dst_and_unlock(self,&ds);/*link*/%N")
               else
                  cpp.put_string(once "ds.caller=se_dst;%N%
                                      %se_dst=&ds;/*link*/%N")
               end
            end
            if rfrt /= Void then
               buffer.clear
               buffer.extend('{')
               rfrt.c_type_for_external_in(buffer)
               buffer.append(once " R=")
               cpp.put_string(buffer)
            end
            create face_target.make(rf.current_type)
            if rf.arguments /= Void then
               eal := effective_arg_list(rf)
            end
            if rfct.is_expanded then
               cpp.push_direct(rf,face_target,eal)
               rf.mapping_c
               cpp.pop
            else
               cpp.push_cpc(rf,run_time_set,face_target,eal)
            end
            if rfrt /= Void then
               cpp.put_string(fz_00)
            end
            if ace.no_check then
               if smart_eiffel.scoop then
                  --*** TO BE FIXED (`self' not defined)
                  cpp.put_string(once "(void)(self->vft.get_dst_and_lock(self));%N%
                                      %self->vft.set_dst_and_unlock(self,caller);/*unlink*/%N")
               else
                  cpp.put_string(once "se_dst=ds.caller;/*unlink*/%N")
               end
            end
            if rfrt /= Void then
               cpp.put_string(once "return R;%N}%N")
            end
         end
         cpp.put_string(fz_12)
      end

feature {CECIL_FILE}

   echo_for(rf: RUN_FEATURE) is
      do
	 if echo.verbose then
	    echo.put_character('%T')
	    echo.put_string(rf.current_type.run_time_mark)
	    echo.put_character('.')
	    echo.put_string(rf.name.to_string)
	    echo.put_character('%N')
	 end
      end

   c_define_for(c_name: STRING; rf: RUN_FEATURE) is
      require
         not c_name.is_empty
         rf /= Void
      local
         rfct, rfrt: E_TYPE
         rfargs: FORMAL_ARG_LIST
      do
         rfct := rf.current_type
         rfrt := rf.result_type
         rfargs := rf.arguments
	 echo_for(rf)
         -- (1) ------------------------- Define Cecil heading :
         buffer.clear
         if rfrt /= Void then
            rfrt.c_type_for_external_in(buffer)
         else
            buffer.append(fz_void)
         end
         buffer.extend(' ')
         buffer.append(c_name)
         buffer.extend('(')
         rfct.c_type_for_external_in(buffer)
         buffer.extend(' ')
         buffer.extend('C')
         if rfargs /= Void then
            buffer.extend(',')
            rfargs.external_prototype_in(buffer)
         end
         buffer.extend(')')
         cpp.put_c_heading(buffer)
         cpp.swap_on_c
         define_body_of(rf)
      end

feature {NONE}

   effective_arg_list(rf: RUN_FEATURE): EFFECTIVE_ARG_LIST is
      local
	 first: FACE_ARGUMENT; remainder: FIXED_ARRAY[EXPRESSION]
	 face_argument: FACE_ARGUMENT; fal: FORMAL_ARG_LIST
	 i: INTEGER
      do
	 fal := rf.arguments
	 create first.make(fal.type(1),1)
	 if fal.count > 1 then
	    from
	       create remainder.with_capacity(fal.count - 1)
	       i := 2
	    until
	       i > fal.count
	    loop
	       create face_argument.make(fal.type(i),i)
	       remainder.add_last(face_argument)
	       i := i + 1
	    end
	    create Result.make_n(first,remainder)
	 else
	    create Result.make_1(first)
	 end
      end

   cecil_files: FIXED_ARRAY[CECIL_FILE]
	 -- Non Void if some -cecil option is used.

   buffer: STRING is
	 -- To prepare C code.
      once
         create Result.make(256)
      end

   singleton_memory: CECIL_POOL is
      once
	 Result := Current
      end

invariant

   is_real_singleton: Current = singleton_memory

end -- CECIL_POOL