------------------------------------------------------------------------------
--                                                                          --
--                            GNATPP COMPONENTS                             --
--                                                                          --
--              G N A T P P . S O U R C E _ T R A V E R S A L               --
--                                                                          --
--                                 B o d y                                  --
--                                                                          --
--                     Copyright (C) 2001-2013, AdaCore                     --
--                                                                          --
-- GNATPP is free software; you can redistribute it  and/or modify it under --
-- terms of the  GNU General Public License as published  by the Free Soft- --
-- ware  Foundation;  either version 2,  or (at your option) any later ver- --
-- sion.  GNATPP is  distributed in the  hope that it will  be  useful, but --
-- WITHOUT ANY WARRANTY; without even the implied warranty of  MERCHANTABI- --
-- LITY 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  distributed with GNAT; see file COPYING. If not, --
-- write to the Free Software Foundation,  51 Franklin Street, Fifth Floor, --
-- Boston,                                                                  --
--                                                                          --
-- GNATPP is maintained by AdaCore (http://www.adacore.com)                 --
--                                                                          --
------------------------------------------------------------------------------

with Ada.Wide_Text_IO;                use Ada.Wide_Text_IO;

with Asis.Elements;                   use Asis.Elements;
with Asis.Extensions.Flat_Kinds;      use Asis.Extensions.Flat_Kinds;

with ASIS_UL.Common;                  use ASIS_UL.Common;

with GNATPP.State;                    use GNATPP.State;
with GNATPP.Pre_Operations;           use GNATPP.Pre_Operations;
with GNATPP.Post_Operations;          use GNATPP.Post_Operations;
with GNATPP.General_Traversal_Stacks; use GNATPP.General_Traversal_Stacks;
with GNATPP.Asis_Utilities;           use GNATPP.Asis_Utilities;
with GNATPP.Paragraphs;               use GNATPP.Paragraphs;
with GNATPP.Options;                  use GNATPP.Options;

package body GNATPP.Source_Traversal is

   --------------------
   -- Post_Operation --
   --------------------

   procedure Post_Operation
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      Arg_Kind : constant Flat_Element_Kinds := Flat_Element_Kind (Element);
   begin

      if (Align_Colons_In_Decl and then
          Contains_Declarations (Arg_Kind))
        or else
          (Align_Asign_In_Stmts and then
           Contains_Statements (Arg_Kind))
        or else
          (Align_Ats and then
           Arg_Kind = A_Record_Representation_Clause)
      then
         Restore_Paragraph;
      end if;

      Get_Current_State;

      Traversal_Stack.Pop;

      --  And now - Element_Kind-specific processing
      Specific_Post_Operation (Arg_Kind) (Element, Control, State);

   exception
      when others =>
         Put (Standard_Error, "Post_Operation failed for");
         New_Line (Standard_Error);
         Put (Standard_Error, Debug_Image (Element));
         New_Line (Standard_Error);

         raise Fatal_Error;
   end Post_Operation;

   -------------------
   -- Pre_Operation --
   -------------------

   procedure Pre_Operation
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      Arg_Kind : constant Flat_Element_Kinds := Flat_Element_Kind (Element);
   begin

      if Can_Be_Aligned (Element) then

         if not In_Paragraph then
            Set_New_Paragraph;
         end if;

      elsif Split_Paragraph (Element) then
         Set_No_Paragraph;
      end if;

      Set_Current_State (Element);

      --  In general Pre_Operation we never deal with end-of-line comments and
      --  comment lines - we start the traversing from the first character
      --  of the Ada code of the unit, and post-operations always process
      --  all the comment and empty lines and leaves the source line buffer
      --  pointing to the ada code.

      --  And now - Element_Kind-specific processing

      Specific_Pre_Operation (Arg_Kind) (Element, Control, State);

      if (Align_Colons_In_Decl and then
          Contains_Declarations (Arg_Kind))
        or else
          (Align_Asign_In_Stmts and then
           Contains_Statements (Arg_Kind))
        or else
          (Align_Ats and then
           Arg_Kind = A_Record_Representation_Clause)
      then
         Save_Paragraph;

         if Arg_Kind = A_Known_Discriminant_Part then
            Increase_Indentation;
         end if;

         Compute_Alignment_In_Paragraphs (Element);

         if Arg_Kind = A_Known_Discriminant_Part then
            Decrease_Indentation;
         end if;

      end if;

      if Control /= Abandon_Children then
         Traversal_Stack.Push (Current_State);
      end if;

   exception
      when others =>
         Put (Standard_Error, "Pre_Operation failed for");
         New_Line (Standard_Error);
         Put (Standard_Error, Debug_Image (Element));
         New_Line (Standard_Error);

         raise Fatal_Error;
   end Pre_Operation;

   --------------------------------------
   -- Traverse_Source_Preserving_State --
   --------------------------------------

   procedure Traverse_Source_Preserving_State
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      Saved_Current_State : Traversal_Step_Record;
   begin
      Saved_Current_State := Current_State;

      Traverse_Source (Element, Control, State);

      Current_State := Saved_Current_State;
   end Traverse_Source_Preserving_State;

end GNATPP.Source_Traversal;
