--          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 FORMAL_ARG_LIST
   --
   -- For the formal arguments list of a routine.
   --

inherit DECLARATION_LIST

creation  make

creation {RUN_FEATURE} with

feature

   name(i: INTEGER): ARGUMENT_NAME1 is
      do
         Result := flat_list.item(i)
      end

   pretty_print is
      local
         i: INTEGER
      do
         pretty_printer.put_character('(')
         pretty_printer.level_incr
         from
            i := list.lower
         until
            i > list.upper
         loop
            list.item(i).pretty_print
            i := i + 1
            if i <= list.upper then
               pretty_printer.put_string(once "; ")
            end
         end
         pretty_printer.level_decr
         pretty_printer.put_character(')')
      end

   short is
      local
         i: INTEGER
      do
         short_print.hook_or(once "hook302",once " (")
         from
            i := list.lower
         until
            i > list.upper
         loop
            list.item(i).short
            i := i + 1
            if i <= list.upper then
               short_print.hook_or(once "hook303",once "; ")
            end
         end
         short_print.hook_or(once "hook306",once ")")
      end

   is_a_in(other: like Current; rc: RUN_CLASS): BOOLEAN is
         -- True when `Current' interpreted in `rc' is a kind of `other'
         -- interpreted in `rc'.
      require
         other /= Void ; rc /= Void
      local
         i: INTEGER; t1, t2: E_TYPE
      do
         i := count
         if other.count /= i then
            error_handler.add_position(other.start_position)
            error(start_position,"Bad number of arguments.")
         end
         if nb_errors = 0 then
            from
               Result := true
            until
               not Result or else i = 0
            loop
               t1 := type(i)
               t2 := other.type(i)
               if not assignment_handler.redefinition(t2,t1,rc,true) then
                  Result := false
                  error_handler.print_as_error
                  error_handler.add_position(t1.start_position)
                  error_handler.add_position(t2.start_position)
                  error_handler.append("Incompatible types in ")
                  error_handler.append(rc.current_type.run_time_mark)
                  error_handler.append(fz_dot_blank)
                  error_handler.print_as_error
               end
               i := i - 1
            end
         end
      end

   verify_scoop(target: EXPRESSION): BOOLEAN is
         -- Verify if the target is an argument of the expression (only when 
         -- the target is separate)
         -- True if any separate expression is target of a call
      local
         i: INTEGER
         arg: ARGUMENT_NAME
         found: BOOLEAN
      do
         arg ?= target
         if arg /= Void and then target.result_type.is_separate and then not target.is_current then
            from
               i := count
            until
               i < 1
            loop
               found := found or else arg.to_string = name(i).to_string
               if name(i).verify_scoop(Current) then
                  Result := true
               end
               i := i - 1
            end
            if not found then
               target.scoop_error
            end
         else
            from
               i := count
            until
               i < 1
            loop
               if name(i).verify_scoop(Current) then
                  Result := true
               end
               i := i - 1
            end
         end
      end

feature {RUN_FEATURE}

   c_frame_descriptor(format, locals: STRING) is
      require
	 ace.no_check
      local
         i: INTEGER; t: E_TYPE
      do
         from
            i := 1
         until
            i > count
         loop
            t := type(i).run_type
	    format.append(name(i).to_string)
	    t.c_frame_descriptor_in(format)
	    locals.append(once "(void**)&a")
	    i.append_in(locals)
	    locals.extend(',')
            i := i + 1
         end
      end

   c_lock_scoop_count: INTEGER

   c_lock_scoop_init is
      require
         smart_eiffel.scoop
      local
         t: E_TYPE
         i, n: INTEGER
      do
         tmp_string.clear
         cpp.put_character('{')
         from
            i := 1
         until
            i > count
         loop
            t := type(i).run_type
            if t.is_separate then
               cpp.put_string(once "NULL,")
               tmp_string.append(once "scoop_sub[")
               n.append_in(tmp_string)
               tmp_string.append(once "]=get_subsystem(a")
               i.append_in(tmp_string)
               tmp_string.append(once ",self);%N")
               n := n + 1
            end
            i := i + 1
         end
         cpp.put_string(once "};%N")
         cpp.put_string(tmp_string)

         c_lock_scoop_count := n
      end

   c_lock_scoop is
      do
         cpp.put_string(once "self->vft.wait_for_providers(self,scoop_sub,")
         cpp.put_integer(c_lock_scoop_count)
         cpp.put_string(once ");%N")
      end

   c_unlock_scoop is
      require
         smart_eiffel.scoop
      do
         cpp.put_string(once "self->vft.unqueue_providers(self, scoop_sub,")
         cpp.put_integer(c_lock_scoop_count)
         cpp.put_string(once ");%N")
      end

feature {RUN_CLASS,RUN_FEATURE}

   compile_to_c_in(c_code_buffer: STRING) is
      local
         i: INTEGER; t: E_TYPE
      do
         from i := 1; until i > count
         loop
            t := type(i).run_type
            t.c_type_for_argument_in(c_code_buffer)
            c_code_buffer.extend(' ')
            c_code_buffer.extend('a')
            i.append_in(c_code_buffer)
            i := i + 1
            if i <= count then
               c_code_buffer.extend(',')
            end
         end
      end

feature {JVM}

   jvm_switch_push(dyn_fal: like Current): INTEGER is
         -- Push inside switching method.
      require
         count = dyn_fal.count
      local
         i: INTEGER
      do
         from i := 1; until i > count
         loop
            Result := Result + jvm_switch_push_ith(dyn_fal,i)
            i := i + 1
         end
      end

feature {JVM}

   jvm_switch_push_ith(dyn_fal: like Current; i: INTEGER): INTEGER is
      local
         ft, at: E_TYPE; offset: INTEGER
      do
         offset := jvm.argument_offset_of(name(i))
         ft := type(i).run_type
         at := dyn_fal.type(i).run_type
         ft.jvm_push_local(offset)
         Result := ft.jvm_convert_to(at)
      end

feature {RUN_FEATURE,SWITCH,NATIVE_SMART_EIFFEL}

   jvm_descriptor_in(buffer: STRING) is
      local
         i: INTEGER; at: E_TYPE
      do
         from
            i := 1
         until
            i > count
         loop
            at := type(i).run_type
            if at.is_reference then
               buffer.append(jvm_root_descriptor)
            else
               at.jvm_descriptor_in(buffer)
            end
            i := i + 1
         end
      end

feature {RUN_FEATURE_3}

   inline_one_pc is
      local
         i: INTEGER; t: E_TYPE
      do
         from
            i := 1
         until
            i > count
         loop
            t := type(i).run_type
            tmp_string.clear
            t.c_type_for_argument_in(tmp_string)
            tmp_string.extend(' ')
            cpp.put_string(tmp_string)
            cpp.inline_level_incr
            cpp.print_argument(i)
            cpp.inline_level_decr
            cpp.put_character('=')
            cpp.put_ith_argument(i)
            cpp.put_string(fz_00)
            i := i + 1
         end
      end

feature {RUN_FEATURE,CECIL_POOL}

   external_prototype_in(str: STRING) is
      local
         i: INTEGER
         t: E_TYPE
      do
         from
            i := 1
         until
            i > count
         loop
            t := type(i).run_type
            t.c_type_for_external_in(str)
            str.extend(' ')
            str.extend('a')
            i.append_in(str)
            i := i + 1
            if i <= count then
               str.extend(',')
            end
         end
      end

feature {E_AGENT}

   open_args(sp: POSITION): EFFECTIVE_ARG_LIST is
	 -- Create the corresponding ommited open arguments list.
      local
	 i, c: INTEGER
      do
	 create Result.make_1(create {OPEN_OPERAND}.make(sp))
         from
	    i := 2
            c := count
         until
            i > c
         loop
            Result.add_last(create {OPEN_OPERAND}.make(sp))
            i := i + 1
         end
      ensure
	 Result.count = count
      end

feature

   has_like_current: BOOLEAN is
      local
	 i: INTEGER
      do
	 from
	    i := flat_list.upper
	 until
	    Result or else i < flat_list.lower
	 loop
	    Result :=  flat_list.item(i).result_type.is_like_current
	    i := i - 1
	 end
      end

feature {NONE}

   make(l: like list) is
	 -- Parsing creation procedure.
      require
         l.lower = 1
         not l.is_empty
      local
         an: like name; tlf: TYPE_LIKE_FEATURE; an2: ARGUMENT_NAME2
	 tla, tla2: TYPE_LIKE_ARGUMENT; i, rank: INTEGER
      do
         declaration_list_make(l)
         -- Substitution TYPE_LIKE_FEATURE/TYPE_LIKE_ARGUMENT:
         from
            i := count
         until
            i = 0
         loop
            an := name(i)
            tlf ?= an.result_type
            if tlf /= Void then
               rank := rank_of(tlf.like_what.to_string)
               if rank = i then
                  error_handler.add_position(tlf.start_position)
                  error_handler.append(fz_cad)
		  error_handler.print_as_fatal_error
               elseif rank > 0 then
                  !!an2.refer_to(tlf.like_what.start_position,Current,rank)
                  !!tla.make(tlf.start_position,an2)
                  an.set_result_type(tla)
               end
            end
            i := i - 1
         end
         if ace.all_check then
            from
               i := count
            until
               i = 0
            loop
               tla ?= name(i).result_type
               if tla /= Void then
                  rank := rank_of(tla.like_what.to_string)
                  tla2 ?= name(rank).result_type
                  if tla2 /= Void then
                     error_handler.add_position(tla.start_position)
                     error_handler.add_position(tla2.start_position)
                     error_handler.append(fz_cad)
		     error_handler.print_as_fatal_error
                  end
               end
               i := i - 1
            end
         end
      ensure
         list = list
         flat_list /= Void
      end

   with(model: like Current; ct: E_TYPE) is
	 -- Runnable creation procedure.
      require
         not model.is_runnable(ct)
      do
         standard_copy(model)
         dynamic_runnable(ct)
         check_name_clash(ct)
      end

   tmp_string: STRING is
      once
         !!Result.make(32)
      end

end -- FORMAL_ARG_LIST