--          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 COMPOUND
   --
   -- An ordered sequence of Eiffel instructions.
   --

inherit GLOBALS

creation {EIFFEL_PARSER,E_PROCEDURE} make_0, make_1

creation {COMPOUND,RUN_CLASS} make

feature

   header_comment: COMMENT
	 -- The one which may be placed at the beginning of the
	 -- compound.

   count: INTEGER is
      do
         if first_one = Void then
         elseif remainder /= Void then
            Result := remainder.upper + 2
         else
            Result := 1
         end
      end

   first: INSTRUCTION is
      require
         count >= 1
      do
         Result := first_one
      ensure
         Result /= Void
      end

   start_position: POSITION is
      do
         if first_one /= Void then
            Result := first_one.start_position
         end
      end

   run_class: RUN_CLASS is
      do
         Result := current_type.run_class
      end

   afd_check is
      local
         i: INTEGER
      do
         from
            i := count
         until
            i = 0
         loop
            item(i).afd_check
            i := i - 1
         end
      end

   safety_check is
      local
         i: INTEGER
      do
         from
            i := count
         until
            i = 0
         loop
            item(i).safety_check
            i := i - 1
         end
      end

   compile_to_c is
      local
         i, c: INTEGER; instruction: INSTRUCTION; need_se_tmp: BOOLEAN
      do
	 from
	    i := 1
	    c := count
	 until
	    i > c
	 loop
	    instruction := item(i)
	    instruction.collect_c_tmp
	    need_se_tmp := cpp.se_tmp_open_declaration
	    instruction.compile_to_c
	    if need_se_tmp then
	       cpp.se_tmp_close_declaration
	    end
	    i := i + 1
	 end
      end

   compile_to_jvm is
      local
         i, c: INTEGER
         instruction: INSTRUCTION
         trace: BOOLEAN
         ca: like code_attribute
      do
         from
            c := count
            ca := code_attribute
            trace := start_position.sedb_trace
            i := 1
         until
            i > c
         loop
            instruction := item(i)
            line_number_table.add(ca.program_counter,
				  instruction.start_position)
            if trace then
               ca.se_trace(current_type,instruction.start_position)
            end
            instruction.compile_to_jvm
            i := i + 1
         end
      end

   use_current: BOOLEAN is
      local
         i: INTEGER
      do
         from
            i := count
         until
            Result or else i = 0
         loop
            Result := item(i).use_current
            i := i - 1
         end
      end

   stupid_switch(run_time_set: RUN_TIME_SET): BOOLEAN is
      local
         i: INTEGER
      do
         from
            Result := true
            i := count
         until
            not Result or else i = 0
         loop
            Result := item(i).stupid_switch(run_time_set)
            i := i - 1
         end
      end

   is_pre_computable: BOOLEAN is
      local
         i: INTEGER
      do
         from
            i := count
            Result := true
         until
            not Result or else i = 0
         loop
            Result := item(i).is_pre_computable
            i := i - 1
         end
      end

   to_runnable(ct: E_TYPE): like Current is
      require
         ct.run_type = ct
         nb_errors = 0
      local
         i: INTEGER; i1, i2: INSTRUCTION; r: like remainder
      do
         if first_one = Void then
            Result := Current
         elseif current_type = Void then
            current_type := ct
            from
               i := count
            until
               i = 0
            loop
               i1 := item(i)
               i2 := i1.to_runnable(ct)
               if nb_errors > 0 then
                  error_handler.append(
				   "Bad instruction (when interpreted in ")
                  error_handler.append(current_type.written_mark)
                  error_handler.add_position(i1.start_position)
                  error_handler.append(").")
		  error_handler.print_as_fatal_error
               else
                  put(i2,i)
               end
               i := i - 1
            end
            Result := Current
         else
	    r := remainder
	    if r /= Void then
	       r := r.twin
	    end
            create Result.make(header_comment,first_one,r)
            Result := Result.to_runnable(ct)
         end
      ensure
         Result /= Void
      end

   pretty_print is
      require
         pretty_printer.indent_level >= 2
      local
         i, c: INTEGER
      do
         c := count
         pretty_printer.level_incr
         pretty_printer.indent
         if header_comment /= Void then
            header_comment.pretty_print
         end
         from
            i := 1
         until
            i > c
         loop
            pretty_printer.set_semi_colon_flag(true)
            if pretty_printer.zen_mode and then i = c then
               pretty_printer.set_semi_colon_flag(false)
            end
            pretty_printer.indent
            item(i).pretty_print
            i := i + 1
         end
         pretty_printer.level_decr
      ensure
         pretty_printer.indent_level = old pretty_printer.indent_level
      end

   empty_or_null_body: BOOLEAN is
      do
         Result := first_one = Void
      end

feature {EIFFEL_PARSER}

   add_last(instruction: INSTRUCTION) is
      require
	 instruction /= Void
      local
	 e_debug: E_DEBUG; e_check: E_CHECK; base_class: BASE_CLASS
      do
	 if smart_eiffel.pretty_flag then
	    perform_add_last(instruction)
	 else
	    e_debug ?= instruction
	    if e_debug /= Void then
	       if ace.debug_check(e_debug) then
		  perform_add_last(e_debug)
	       end
	    else
	       e_check ?= instruction
	       if e_check /= Void then
		  base_class := e_check.start_position.base_class
		  if base_class.all_check then
		     perform_add_last(e_check)
		  end
	       else
		  perform_add_last(instruction)
	       end
	    end
	 end
      ensure
	 count.in_range(old count,1 + old count)
      end

feature

   verify_scoop(allowed: FORMAL_ARG_LIST) is
      local
         i: INTEGER
      do
         from
            i := count
         until
            i = 0
         loop
            item(i).verify_scoop(allowed)
            i := i - 1
         end
      end

feature {COMPOUND}

   first_one: INSTRUCTION
         -- The `first_one' if any.

   remainder: FIXED_ARRAY[INSTRUCTION]
         -- Non Void when the list has more than one element.

   item(i: INTEGER): INSTRUCTION is
      require
         i.in_range(1,count)
      do
         if i = 1 then
            Result := first_one
         else
            Result := remainder.item(i - 2)
         end
      end

feature {NONE}

   current_type: E_TYPE
         -- Not Void when checked in.

   make_0(hc: like header_comment) is
      require
         hc /= Void
      do
         header_comment := hc
      ensure
         header_comment = hc
      end

   make_1(hc: like header_comment; fo: like first_one) is
      require
         fo /= Void
      do
         header_comment := hc
	 add_last(fo)
      ensure
         header_comment = hc
      end

   make(hc: like header_comment; fo: like first_one; r: like remainder) is
      require
         hc /= Void or else fo /= Void
         r /= Void implies fo /= Void
      do
         header_comment := hc
         first_one := fo
         remainder := r
      ensure
         header_comment = hc
         first_one = fo
         remainder = r
      end

   put(i: INSTRUCTION; idx: INTEGER) is
      require
         i /= Void
         idx.in_range(1,count)
      do
         if idx = 1 then
            first_one := i
         else
            remainder.put(i,idx - 2)
         end
      end

   perform_add_last(instruction: INSTRUCTION) is
	 -- Really perform the `add_last'.
      require
	 instruction /= Void
      do
	 if first_one = Void then
	    first_one := instruction
	 else
	    if remainder = Void then
	       create remainder.with_capacity(8)
	    end
	    remainder.add_last(instruction)
	 end
      ensure
	 count = 1 + old count
      end

invariant

   remainder /= Void implies first_one /= Void

end -- COMPOUND
