--          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.
--
deferred class CREATE_TOOLS
--
-- Common root for OLD_CREATION, CREATE_INSTRUCTION and CREATE_EXPRESSION
--

inherit GLOBALS

feature

   frozen afd_check is
      local
	 args: like arguments
      do
	 args := arguments
	 if args /= Void then
	    args.afd_check
	 end
      end

   frozen safety_check is
      local
	 args: like arguments
      do
	 args := arguments
	 if args /= Void then
	    args.safety_check
	 end
      end

feature {NONE}

   start_position: POSITION

   type: E_TYPE
         -- Explicit optional generator name if any.

   writable: EXPRESSION
         -- If any, the target of the creation call.

   call: PROC_CALL
         -- Optional initialisation call if any. (The target of `call' is
         -- the `writable' entity.)

   run_feature: RUN_FEATURE
         -- When checked, if any, the only one corresponding creation
         -- procedure.

   current_type: E_TYPE
         -- Not Void when checked in this context.

   check_create_clause(t: E_TYPE) is
	 -- Where `t' is the TYPE to create.
      require
         t.is_run_type
      local
         fn: FEATURE_NAME; bottom, top: BASE_CLASS; args: like arguments
	 arg_count: INTEGER; w: like writable; rc: RUN_CLASS

         bf: E_FEATURE; -- DEBUG
      do
	 rc := t.run_class
	 if call = Void then
	    run_feature := rc.a_default_create
	    if run_feature /= Void then
	    elseif t.base_class.has_creation_clause then
	       error_handler.append("Creation clause exists for ")
	       error_handler.add_type(t,". ")
	       error(start_position,"You must use a constructor.")
	    end
	 else
	    fn := call.feature_name
	    top := fn.start_position.base_class
	    bottom := t.base_class
	    if t.is_like_current then
	       check
		  bottom = top or else bottom.is_subclass_of(top)
	       end
	       fn := bottom.new_name_of(top,fn)
	       if fn = Void then
		  fn := call.feature_name
		  error_handler.feature_not_found(fn)
		  error_handler.append(" Type to create is %"")
		  error_handler.append(t.run_time_mark)
		  fatal_error(fz_03)
	       end
	    end
	    run_feature := rc.get_feature(fn)
	    if run_feature = Void then
	       cp_not_found(fn)
	    else
               bf := run_feature.base_feature
	       run_feature.base_feature.check_obsolete(fn.start_position)
	    end
	    if smart_eiffel.short_flag then
	    elseif not rc.base_class.has_creation(fn) then
	       error_handler.add_position(call.feature_name.start_position)
	       error_handler.add_position(fn.start_position)
	       error_handler.append(fn.to_string)
	       error_handler.append(" is not in the creation list of ")
	       error_handler.add_type(t,fz_dot_blank)
	       error_handler.print_as_fatal_error
	    end
	    run_feature.run_class.add_client(current_type.run_class)
	    if run_feature.result_type /= Void then
	       error_handler.add_position(run_feature.start_position)
	       error_handler.add_position(fn.start_position)
	       fatal_error(fz_ffinap)
	    end
	    arg_count := arguments_count
	    if arg_count > 0 then
	       args := arguments.to_runnable(current_type)
	       if args = Void then
		  error(call.arguments.start_position,fz_bad_arguments)
	       end
	    end
	    smart_eiffel.argument_passing_check(call.start_position,
						args,run_feature)
	    w := writable
	    if w = Void then
	       w := call.target
	    end
	    call := call.runnable_create(current_type,w,args,run_feature)
	 end
      end

   arguments: EFFECTIVE_ARG_LIST is
      do
	 if call /= Void then
	    Result := call.arguments
	 end
      end

   arguments_count: INTEGER is
      do
         if call /= Void then
            Result := call.arg_count
         end
      end

   cp_not_found(fn: FEATURE_NAME) is
      do
         error_handler.add_position(call.feature_name.start_position)
         error_handler.add_position(fn.start_position)
         fatal_error("Creation procedure not found.")
      end

   check_created_type(t: E_TYPE) is
      require
         t.is_run_type
      local
         rt: like t
      do
         rt := t.run_type
         if smart_eiffel.short_flag then
         elseif rt.base_class.is_deferred then
            error_handler.add_type(rt," is deferred. ")
            warning(start_position,"Cannot create object.")
         end
         if t.is_formal_generic then
            error_handler.add_position(start_position)
            error_handler.append("Creation call on formal generic type (")
            error_handler.add_type(t,").")
            error_handler.print_as_fatal_error
         end
         if t.is_separate then
            smart_eiffel.set_scoop
         end
         rt.run_class.set_at_run_time
      end

   check_explicit_type is
      require
	 type /= Void
      local
         t, destination_type: E_TYPE
      do
         t := type.to_runnable(current_type)
         if t = Void or else not t.is_run_type then
            error_handler.add_position(type.start_position)
            fatal_error("Invalid explicit type.")
         else
            type := t
         end
	 if writable /= Void then
	    destination_type := writable.result_type
	    if not type.is_a(destination_type) then
	       fatal_error(" Bad explicit type mark.")
	    end
	    if type.run_time_mark /= destination_type.run_time_mark then
	       assignment_handler.assignment(type.start_position,
					     type,
					     destination_type)
	    end
	 end
      end

   compile_to_jvm0(t: E_TYPE) is
         -- Push the new object with default initialization.
      require
         t /= Void
      local
         dummy: INTEGER
      do
         if t.is_reference then
            t.run_class.jvm_basic_new
         else
            dummy := t.jvm_push_default
         end
      end

invariant

   not start_position.is_unknown

end -- CREATE_TOOLS
