------------------------------------------------------------------------------
--                                                                          --
--                            GNATPP COMPONENTS                             --
--                                                                          --
--                G N A T P P . P R E _ O P E R A T I O N S                 --
--                                                                          --
--                                 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).                --
--                                                                          --
------------------------------------------------------------------------------

pragma Ada_2012;

with Asis.Clauses;                    use Asis.Clauses;
with Asis.Elements;                   use Asis.Elements;
with Asis.Declarations;               use Asis.Declarations;
with Asis.Definitions;                use Asis.Definitions;
with Asis.Statements;                 use Asis.Statements;
with Asis.Expressions;                use Asis.Expressions;
with Asis.Extensions;                 use Asis.Extensions;
with Asis.Text;                       use Asis.Text;

with Ada_Trees.Formatting; use Ada_Trees.Formatting;

with GNATPP.Asis_Utilities;           use GNATPP.Asis_Utilities;
with GNATPP.Comments;                 use GNATPP.Comments;
with GNATPP.General_Traversal_Stacks; use GNATPP.General_Traversal_Stacks;
with GNATPP.Layout;                   use GNATPP.Layout;
with GNATPP.Options;                  use GNATPP.Options;
with GNATPP.Paragraphs;               use GNATPP.Paragraphs;
with GNATPP.PP_Output;                use GNATPP.PP_Output;
with GNATPP.Source_Line_Buffer;       use GNATPP.Source_Line_Buffer;
with GNATPP.Source_Traversal;
with GNATPP.State;                    use GNATPP.State;
with GNATPP.Utilities;                use GNATPP.Utilities;

with A4G.Skip_TB;

package body GNATPP.Pre_Operations is

   -----------------------
   -- Local Subprograms --
   -----------------------

   procedure PP_Labels (Statement : Asis.Element);
   --  Provided that Statement is A_Statement Element, pretty-prints it labels,
   --  if any

   function Share_Prefix (Use_Clause : Asis.Element) return Boolean;
   --  This function is used to check if the argument use clause should
   --  be placed at the same line as previous with clause because it chares
   --  the prefix of the name with this with clause.
   --  It is supposed that the argument is a (package or type) use clause from
   --  a context clause.
   --  The name from the previous with clause is supposed to be stored in
   --  GNATPP.State.Prev_Element. If it contains Nil_Element, this function
   --  returns False.
   --  If GNATPP.State.Prev_Element is not Is_Nil, the function checks if each
   --  name from the argument use clause corresponds to the package name from
   --  the previous with clause. This means the following. If the name from
   --  the with clause is A.B.C, then the corresponding names in the use
   --  package clause are A, A.B, A.B.C, and the corresponing names in the use
   --  type clause are these names appended with a (type) name.
   --
   --  If this function returns False, it sets GNATPP.State.Prev_Element to
   --  Nil_Element.

   ------------------------
   -- A_Case_Path_Pre_Op --
   ------------------------

   procedure A_Case_Path_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      PP_New_Line;
      PP_Keyword (KW_When);
      Get_Next_Ada_Lexem;

      PP_Continue_Line_Postponed;

      Compute_Case_Choices_Layout (Element);

      Increase_Indentation;
   end A_Case_Path_Pre_Op;

   -----------------------------
   -- A_Case_Statement_Pre_Op --
   -----------------------------

   procedure A_Case_Statement_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      Alternative_Number : Positive;
   begin
      PP_New_Line;

      PP_Labels (Element);

      PP_Keyword (KW_Case);
      Get_Next_Ada_Lexem;
      PP_Continue_Line;

      if Flat_Element_Kind (Element) = A_Case_Statement then
         Alternative_Number := Statement_Paths (Element)'Length;
      else
         Alternative_Number := Variants (Element)'Length;
      end if;

      if Alternative_Number < Case_Threshold then
         Increase_Indentation;
      end if;

   end A_Case_Statement_Pre_Op;

   -------------------------------------------
   -- A_Defining_Enumeration_Literal_Pre_Op --
   -------------------------------------------

   procedure A_Defining_Enumeration_Literal_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      if Enum_Literal_Def_On_Separate_Lines then
         PP_New_Continuation_Line;
      end if;

      if Flat_Element_Kind (Element) = A_Defining_Enumeration_Literal then
         PP_Word (Capitalize (Element, PP_Enum_Literal_Casing));
      else

         PP_Word (Line_Buf (Current_State.The_Span.First_Column ..
                            Current_State.The_Span.Last_Column));
      end if;

      Get_Next_Ada_Lexem;

      Detect_Delimiter;

      if Delimiter = Comma_Dlm then

         if Is_New_Output_Line then
            PP_New_Continuation_Line;
         end if;

         PP_Delimiter (Comma_Dlm);
         Get_Next_Ada_Lexem (Keep_Empty_Lines => True);

         if not Enum_Literal_Def_On_Separate_Lines then
            PP_Space;
         end if;

      end if;

   end A_Defining_Enumeration_Literal_Pre_Op;

   ----------------------------------
   -- A_Defining_Identifier_Pre_Op --
   ----------------------------------

   procedure A_Defining_Identifier_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      Enclosing_El_Kind : Flat_Element_Kinds;
      Enclosing_El      : Asis.Element;
      Adjust            : Integer   := 1;
      Casing            : PP_Casing := PP_Name_Casing;
   begin

      --  ??? Should be rewritten on the base of a loop, similar to
      --  An_Expression_Post_Op???

      Enclosing_El_Kind := Get_Enclosing_Kind;

      if Is_Label (Element) then
         return;
      end if;

      if Adds_Indentation (Enclosing_El_Kind) then
         Adjust := 0;
      else
         Adjust := 1;
      end if;

      if not Is_New_Output_Line then

         if not Declaration_Starts_From_Def_Name (Enclosing_El_Kind) then
            PP_Space;
         end if;

      else

         if not Declaration_Starts_From_Def_Name (Enclosing_El_Kind) then
            PP_New_Line (Adjust_Depth => Adjust, Backspace => 1);
         end if;

      end if;

      if Flat_Element_Kind (Element) in Flat_Defining_Operator_Kinds then
         --  We are treading operators as keywords
         PP_Word
           (Capitalize_Image
             (Line_Buf
                (Current_State.The_Span.First_Column ..
                   Current_State.The_Span.Last_Column), PP_Keyword_Casing));
      else
         case Enclosing_El_Kind is
            when A_Subtype_Declaration                |
                 An_Ordinary_Type_Declaration         |
                 A_Task_Type_Declaration              |
                 A_Protected_Type_Declaration         |
                 An_Incomplete_Type_Declaration       |
                 A_Tagged_Incomplete_Type_Declaration |
                 A_Private_Type_Declaration           |
                 A_Private_Extension_Declaration      |
                 A_Formal_Type_Declaration            |
                 A_Formal_Incomplete_Type_Declaration =>
               Casing := PP_Type_Casing;
            when A_Task_Body_Declaration      |
                 A_Protected_Body_Declaration =>
               Enclosing_El := Get_Enclosing_Element;
               Enclosing_El := Corresponding_Declaration (Enclosing_El);

               if Declaration_Kind (Enclosing_El) in
                  A_Task_Type_Declaration .. A_Protected_Type_Declaration
               then
                  Casing := PP_Type_Casing;
               end if;
            when An_Integer_Number_Declaration |
                 A_Real_Number_Declaration     =>
               Casing := PP_Nnumbers_Casing;
            when others => null;
         end case;

         PP_Word (Capitalize (Element, Casing));
      end if;

      Get_Next_Ada_Lexem;

   end A_Defining_Identifier_Pre_Op;

   --------------------------------------
   -- A_Derived_Type_Definition_Pre_Op --
   --------------------------------------

   procedure A_Derived_Type_Definition_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      PP_Continue_Line;

      Detect_Keyword;

      while Keyword /= KW_New loop
         PP_Keyword (Keyword);
         Get_Next_Ada_Lexem;
         Detect_Keyword;
         PP_Continue_Line;
      end loop;

      PP_Keyword (Keyword);
      Get_Next_Ada_Lexem;
   end A_Derived_Type_Definition_Pre_Op;

   ------------------------------
   -- A_Discrete_Choice_Pre_Op --
   ------------------------------

   procedure A_Discrete_Choice_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      case Get_Enclosing_Kind is

         when A_Record_Component_Association ..
              An_Array_Component_Association =>

            null;

         when A_Case_Path |
              A_Variant   =>

            if Choice_On_Separate_Line then
               PP_Pad_Up_To (Choice_Start_Pos);
            end if;

         when others =>

            if Last_Dlm /= Left_Parenthesis_Dlm then
               PP_Continue_Line_Postponed;
            end if;

            Compute_Simple_Expression_Range_Layout (Element);

      end case;
   end A_Discrete_Choice_Pre_Op;

   ------------------------------------------
   -- A_Discrete_Subtype_Definition_Pre_Op --
   ------------------------------------------

   procedure A_Discrete_Subtype_Definition_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      if Get_Enclosing_Kind = An_Entry_Declaration then
         --  Too primitive! Needs revising!
         PP_Continue_Line (No_Space => RM_Style_Spacing);
         PP_Delimiter (Left_Parenthesis_Dlm);
         Get_Next_Ada_Lexem;
      else
         --  A constrained array definition... What else???

         if Get_Enclosing_Kind = A_Loop_Parameter_Specification then
            Compute_Simple_Expression_Range_Layout (Element);

         elsif Start_Index_Def_From_New_Line then

            if Last_Dlm = Left_Parenthesis_Dlm then

               if Is_New_Output_Line then
                  PP_New_Line_For_Index_Def;
               end if;

            else
               PP_New_Line_For_Index_Def;
            end if;

         elsif Last_Dlm /= Left_Parenthesis_Dlm then
            PP_Space;
         end if;

      end if;

   end A_Discrete_Subtype_Definition_Pre_Op;

   -----------------------------------------
   -- A_Discriminant_Specification_Pre_Op --
   -----------------------------------------

   procedure A_Discriminant_Specification_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

   begin

      if Discriminants_On_Separate_Lines then

         if Output_Pos /= (Logical_Depth + 1) * PP_Indentation + 1 then
            --  A trick to detect the first discriminant specification
            PP_New_Line (Adjust_Depth => 1);
         end if;

      elsif Last_Dlm /= Left_Parenthesis_Dlm then
         PP_Space;
      end if;

   end A_Discriminant_Specification_Pre_Op;

   ---------------------------------------------
   -- A_Formal_Private_Type_Definition_Pre_Op --
   ---------------------------------------------

   procedure A_Formal_Private_Type_Definition_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      Detect_Keyword;

      while Keyword /= Not_A_KW loop
         PP_Continue_Line;
         PP_Keyword (Keyword);
         Get_Next_Ada_Lexem;
         Detect_Keyword;
      end loop;

   end A_Formal_Private_Type_Definition_Pre_Op;

   -------------------------------------
   -- A_Fixed_Point_Definition_Pre_Op --
   -------------------------------------

   procedure A_Fixed_Point_Definition_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      --  ???  This is very similar to A_Signed_Integer_Type_Definition_Pre_Op

      PP_Continue_Line;

      PP_Keyword (KW_Delta);

      Get_Next_Ada_Lexem;

      PP_Continue_Line;

   end A_Fixed_Point_Definition_Pre_Op;

   ----------------------------------------
   -- A_Floating_Point_Definition_Pre_Op --
   ----------------------------------------

   procedure A_Floating_Point_Definition_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      --  ???  This is very similar to A_Signed_Integer_Type_Definition_Pre_Op
      --  ???  and to A_Fixed_Point_Definition_Pre_Op and to
      --  ???  A_Modular_Type_Definition_Pre_Op,
      --  ???  A_Simple_Expression_Range_Pre_Op

      PP_Continue_Line;

      PP_Keyword (KW_Digits);

      Get_Next_Ada_Lexem;

      PP_Continue_Line;

   end A_Floating_Point_Definition_Pre_Op;

   --------------------------------------------
   -- A_Formal_Scalar_Type_Definition_Pre_Op --
   --------------------------------------------

   procedure A_Formal_Scalar_Type_Definition_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      PP_Continue_Line;

      Detect_Delimiter;

      if Delimiter = Left_Parenthesis_Dlm then
         PP_Continue_Line  (No_Space => RM_Style_Spacing);
         --  formal_discrete_type_definition ::= (<>)
         PP_Delimiter (Left_Parenthesis_Dlm);

         Get_Next_Ada_Lexem;

         if Is_New_Output_Line then
            PP_New_Continuation_Line;
         end if;

         PP_Delimiter (Box_Dlm);

         Get_Next_Ada_Lexem;

         if Is_New_Output_Line then
            PP_New_Continuation_Line;
         end if;

         PP_Delimiter (Right_Parenthesis_Dlm);

         Get_Next_Ada_Lexem;

         return;
      else
         PP_Continue_Line;
      end if;

      Detect_Keyword;
      PP_Keyword (Keyword);
      Get_Next_Ada_Lexem;

      PP_Continue_Line;

      PP_Delimiter (Box_Dlm);

      Get_Next_Ada_Lexem;

      Detect_Keyword;

      if Keyword = KW_Digits then
         --  formal_decimal_fixed_point_definition ::= delta <> digits <>
         PP_Continue_Line;
         PP_Keyword (Keyword);
         Get_Next_Ada_Lexem;

         PP_Continue_Line;

         PP_Delimiter (Box_Dlm);

         Get_Next_Ada_Lexem;

      end if;

   end A_Formal_Scalar_Type_Definition_Pre_Op;

   ----------------------------
   -- A_Function_Call_Pre_Op --
   ----------------------------

   procedure A_Function_Call_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      State.Put_Postponed_Space := False;
      A_General_Expression_Pre_Op (Element, Control, State);
      State := Initial_State;

      if Is_Prefix_Call (Element) then
         Compute_Call_Layout (Element);
      else
         Compute_Infix_Call_Layout (Element);
      end if;

      if Move_All_Call_Left then
         if Start_Call_Pos = 1 then
            --  This is really a kind of ad-hoc patch for bad placement of
            --  a function call...
            PP_New_Continuation_Line;
         else
            PP_New_Line_And_Pad (Start_Call_Pos);
         end if;
      else
         PP_Postponed_Space;
      end if;

      if ASIS_2005_Mode
        and then
         Is_Prefix_Notation (Element)
      then

         declare
            Local_Control : Traverse_Control       := Continue;
            Local_State   : Source_Traversal_State := Initial_State;
            First_Par     : constant Asis.Element :=
              Get_First_Par (Element);
         begin

            GNATPP.Source_Traversal.Traverse_Source_Preserving_State
              (First_Par, Local_Control, Local_State);

         end;

      end if;

   end A_Function_Call_Pre_Op;

   ---------------------------------
   -- A_General_Expression_Pre_Op --
   ---------------------------------

   procedure A_General_Expression_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      pragma Unreferenced (Control);

      Arg_Kind : constant Flat_Element_Kinds :=  Flat_Element_Kind (Element);

      Is_Very_Long_Expression : Boolean := False;
      Start_Expr_On_Next_Line : Boolean := False;

      Tmp               : Natural := 0;
      Too_Long_Terminal : Boolean := False;

      Expr_Space     : Natural;
      Room_For_Space : Natural := 0;
      Has_Comments   : Boolean;
      pragma Warnings (Off, Has_Comments);
      --  Next_Space is used as placeholder parameter in the call to
      --  Detect_Possible_Layout

      Encl_El   : constant Asis.Element       := Get_Enclosing_Element;
      Encl_Kind : constant Flat_Element_Kinds := Get_Enclosing_Kind;
   begin

      if Encl_Kind = An_And_Then_Short_Circuit or else
         Encl_Kind = An_Or_Else_Short_Circuit
      then

         if Encl_Kind = An_And_Then_Short_Circuit then
            Set_Is_And_Then_Arg;
         else
            Set_Is_Or_Else_Arg;
         end if;

         if Pars_On_Sep_Lines then

            if Output_Pos <= Start_Par_Pos then
               PP_Pad_Up_To (Start_Par_Pos);
            else
               PP_Space_If_Needed;
            end if;

         end if;

      end if;

      if Encl_Kind = A_Qualified_Expression
        and then
          (Flat_Element_Kind (Element) not in
             A_Record_Aggregate .. A_Named_Array_Aggregate
          or else
           A4G.Skip_TB.Needs_Extra_Parentheses (Element))
        and then
          Is_Equal (Converted_Or_Qualified_Expression (Encl_El), Element)
      then

         if Is_New_Output_Line then
            PP_New_Continuation_Line;
         end if;

         PP_Delimiter (Left_Parenthesis_Dlm);
         Get_Next_Ada_Lexem;

      elsif Has_Choices (Encl_Kind) then

         if Choice_On_Separate_Line then
            PP_Pad_Up_To (Choice_Start_Pos);
         end if;

      elsif May_Have_Init_Expr (Encl_Kind) then

         if Init_Expr_On_Separate_Line and then
            not Is_New_Output_Line
         then
            PP_New_Continuation_Line;
         end if;

      elsif Encl_Kind not in Flat_Expression_Kinds and then
            ((Encl_Kind /= A_Subtype_Indication and then
            (Last_KW = KW_Is
               or else
             Last_KW = KW_When
               or else
             Last_KW = KW_And))
           or else
             (Encl_Kind = A_Formal_Derived_Type_Definition and then
              Last_KW = KW_New)
           or else
              Encl_Kind = A_While_Loop_Statement)
      then
         PP_Continue_Line;
      end if;

      if Is_Assignment_Expression (Element)
        or else
         (Last_Dlm = Arrow_Dlm and then
          Arg_Kind not in A_Record_Aggregate .. A_Named_Array_Aggregate)
      then

         --  We have to check if we should start the expression from the new
         --  line

         Is_Very_Long_Expression :=
            (Current_State.The_Span.Last_Line -
             Current_State.The_Span.First_Line) > 5;
         --  This is a rather rough approach. The idea is that if in the
         --  argument source the expression occupies more than 5 lines then in
         --  the result source it will hardly be placed into one line. The
         --  better approach would be to compute the space needed for
         --  the expression without comments if any.

         if not Is_Very_Long_Expression then
            Detect_Possible_Layout
              (The_Element     => Element,
               Space_In_Output => Expr_Space,
               Comment_Inside  => Has_Comments);
         end if;

         if Postponed_Space and then
            not Space_Just_Printed
         then
            Room_For_Space := 1;
         end if;

         if Is_Very_Long_Expression or else
            (Output_Pos + Expr_Space + 1 + Room_For_Space >
             Max_Line_Length)
         then
            Start_Expr_On_Next_Line := True;

            --  But there is a chance to split the expression in some
            --  reasonable way

            if not Is_Very_Long_Expression and then
               (Arg_Kind in An_And_Then_Short_Circuit ..
                A_Not_In_Membership_Test
              or else
                (Arg_Kind = A_Function_Call   and then
                 not Is_Prefix_Call (Element) and then
                 not Is_Unary (Flat_Element_Kind (Prefix (Element)))))
            then

               Detect_Possible_Layout
                 (The_Element     => First_Operand (Element),
                  Space_In_Output => Expr_Space,
                  Comment_Inside  => Has_Comments);

               if Output_Pos + Expr_Space + 1 + Room_For_Space <=
                  Max_Line_Length
               then
                  Start_Expr_On_Next_Line := False;
               end if;

            end if;

            if Start_Expr_On_Next_Line and then not
               Is_Prefix_Call (Element)
            then

               if Encl_Kind = A_Parameter_Association or else
                  Encl_Kind = A_Pragma_Argument_Association
               then
                  Tmp := Start_Par_Pos (1);

                  if not (Is_Terminal_Element (Element) and then
                          Expr_Space + Tmp + PP_Cont_Line_Indentation >
                          Max_Line_Length)
                  then
                     --  Otherwise there is no reason to set up the
                     --  continuation line
                     PP_New_Line_And_Pad (Tmp + PP_Cont_Line_Indentation);
                  else
                     Too_Long_Terminal := True;
                  end if;

               else
                  if not (Is_Terminal_Element (Element) and then
                          Expr_Space + Logical_Depth * PP_Indentation +
                          PP_Cont_Line_Indentation > Max_Line_Length)
                  then
                     --  Otherwise there is no reason to set up the
                     --  continuation line
                     PP_New_Continuation_Line;
                  else
                     Too_Long_Terminal := True;
                  end if;

               end if;

            else
               PP_Continue_Line_Postponed;
            end if;

         elsif not Is_Prefix_Call (Element) then
            PP_Postponed_Space;
         end if;

      end if;

      if State.Put_Postponed_Space                and then
         not Start_Range_Expression_From_New_Line and then
         not Too_Long_Terminal
      then
         PP_Postponed_Space;
         --  ??? Should we remove this from pre-ops
         --   for specific expression kinds?
      elsif Start_Range_Expression_From_New_Line then
         PP_New_Continuation_Line;
      end if;

   end A_General_Expression_Pre_Op;

   --------------------------------
   -- A_General_Statement_Pre_Op --
   --------------------------------

   procedure A_General_Statement_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      PP_New_Line;
      --  ??? What else? Seems to be a common thing for many constructs

      PP_Labels (Element);

      if Is_Call (Element) then
         Compute_Call_Layout (Element);

         if ASIS_2005_Mode
           and then
            Is_Prefix_Notation (Element)
         then

            declare
               Local_Control : Traverse_Control       := Continue;
               Local_State   : Source_Traversal_State := Initial_State;
               First_Par     : constant Asis.Element :=
                 Get_First_Par (Element);
            begin

               GNATPP.Source_Traversal.Traverse_Source_Preserving_State
                 (First_Par, Local_Control, Local_State);

            end;

         end if;

      end if;

      Detect_Keyword;

      if not (Keyword = Not_A_KW      or else
            --  We have to allow to use Ada 2005 keywords as identifiers in
            --  Ada 95 programs, see F406-003
              Keyword = KW_Overriding or else
              Keyword = KW_Interface  or else
              Keyword = KW_Synchronized)
      then
         PP_Keyword (Keyword);
         Get_Next_Ada_Lexem;

         --  ???The following is not good!

         if not (Keyword = KW_Exit
               or else
                 Keyword = KW_Terminate
               or else
                (Keyword = KW_Raise
                and then Is_Nil (Raised_Exception (Element)))
               or else
                (Statement_Kind (Element) = A_Return_Statement
                and then Is_Nil (Return_Expression (Element))))
         then
            PP_Continue_Line_Postponed;
         end if;

         if Keyword = KW_Delay then
            Detect_Keyword;

            if Keyword /= Not_A_KW then

               if Keyword = KW_Until then
                  PP_Continue_Line;
               end if;

               PP_Keyword (Keyword);
               Get_Next_Ada_Lexem;
               PP_Continue_Line;
            end if;

         end if;

      end if;

   end A_General_Statement_Pre_Op;

   ----------------------------------
   -- A_Generic_Declaration_Pre_Op --
   ----------------------------------

   procedure A_Generic_Declaration_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      PP_New_Line;

      Detect_Keyword;

      if Keyword = KW_Private then
         PP_Keyword (Keyword);
         Get_Next_Ada_Lexem (Keep_Empty_Lines => True);
         PP_Continue_Line;
      end if;

      PP_Keyword (KW_Generic);
      Increase_Indentation;
      Get_Next_Ada_Lexem (Keep_Empty_Lines => True);

      Detect_Keyword;

      case Keyword is
         when  KW_Procedure |
               KW_Function  |
               KW_Package   =>

            PP_New_Line (Adjust_Depth => -1);
            PP_Keyword (Keyword);
            Get_Next_Ada_Lexem;
         when others =>
            null;
      end case;

      if Flat_Element_Kind (Element) in
         A_Generic_Procedure_Declaration .. A_Generic_Function_Declaration
      then
         Is_First_Parameter_Spec := True;
      end if;

   end A_Generic_Declaration_Pre_Op;

   --------------------------------------
   -- A_Known_Discriminant_Part_Pre_Op --
   --------------------------------------

   procedure A_Known_Discriminant_Part_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      Compute_Discriminants_Layout (Element);

      if Discriminants_On_Separate_Lines then
         PP_New_Continuation_Line;
      else
         PP_Space;
      end if;

      PP_Continue_Line (No_Space => RM_Style_Spacing);

      PP_Delimiter (Left_Parenthesis_Dlm);

      Get_Next_Ada_Lexem;

   end A_Known_Discriminant_Part_Pre_Op;

   ----------------------
   -- A_Literal_Pre_Op --
   ----------------------

   procedure A_Literal_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      A_General_Expression_Pre_Op (Element, Control, State);

      PP_Word
        (Line_Buf (Current_State.The_Span.First_Column ..
                   Current_State.The_Span.Last_Column));

      Get_Next_Ada_Lexem;

   end A_Literal_Pre_Op;

   --------------------------------------
   -- A_Modular_Type_Definition_Pre_Op --
   --------------------------------------

   procedure A_Modular_Type_Definition_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      --  ???  This is very similar to A_Signed_Integer_Type_Definition_Pre_Op

      PP_Continue_Line;

      PP_Keyword (KW_Mod);

      Get_Next_Ada_Lexem;

      PP_Continue_Line;

   end A_Modular_Type_Definition_Pre_Op;

   ------------------------------
   -- A_Named_Statement_Pre_Op --
   ------------------------------

   procedure A_Named_Statement_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      --   ??? Named blocks???

      PP_New_Line;

      PP_Labels (Element);

      Detect_Keyword;

      if Keyword /= Not_A_KW then
         PP_Keyword (Keyword);
         Get_Next_Ada_Lexem (Keep_Empty_Lines => True);

         if Keyword = KW_Declare then
            Detect_Keyword;

            if Keyword = KW_Begin then
               PP_New_Line;
               PP_Keyword (Keyword);
               Get_Next_Ada_Lexem (Keep_Empty_Lines => True);

            end if;

         end if;

      end if;

      Increase_Indentation;

      if Flat_Element_Kind (Element) = An_Accept_Statement or else
         Flat_Element_Kind (Element) = A_While_Loop_Statement
      then
         PP_Continue_Line;
      end if;

      Is_First_Parameter_Spec := True;

   end A_Named_Statement_Pre_Op;

   -------------------------------------
   -- A_Null_Record_Definition_Pre_Op --
   -------------------------------------

   procedure A_Null_Record_Definition_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      Len : Natural := 13;  -- " null record;"
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      --  Note that if we have a null record definition as a record extension,
      --  and if it comes after a discriminant constraint, the WITH keyword
      --  is not printed out by An_Expression_Post_Op (D105-004)

      Detect_Keyword;

      if Keyword = KW_With then
         Len := Len + 5;
      end if;

      if Available_In_Output > KW_Length (Keyword) then
         PP_Continue_Line;
      else
         PP_New_Continuation_Line;
      end if;

      loop
         PP_Keyword (Keyword);
         Get_Next_Ada_Lexem;
         exit when Keyword = KW_Record;
         PP_Continue_Line;
         Detect_Keyword;
      end loop;

      Get_Next_Ada_Lexem;
   end A_Null_Record_Definition_Pre_Op;

   -----------------------------
   -- A_Null_Statement_Pre_Op --
   -----------------------------

   procedure A_Null_Statement_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin

      if Flat_Element_Kind (Element) /= A_Null_Literal then
         PP_New_Line;
         PP_Labels (Element);
      else
         A_General_Expression_Pre_Op (Element, Control, State);
      end if;

      PP_Keyword (KW_Null);
      Get_Next_Ada_Lexem;
   end A_Null_Statement_Pre_Op;

   ---------------------------------------
   --  A_Parameter_Specification_Pre_Op --
   ---------------------------------------

   procedure A_Parameter_Specification_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      Encl_Kind : constant Flat_Element_Kinds := Get_Enclosing_Kind;
      Ident     : Integer                     := 0;
   begin

      case Encl_Kind is

         when A_Procedure_Declaration                    |
              A_Null_Procedure_Declaration               |
              A_Function_Declaration                     |
              A_Formal_Procedure_Declaration             |
              A_Formal_Function_Declaration              |
              A_Procedure_Renaming_Declaration           |
              A_Function_Renaming_Declaration            |
              An_Entry_Declaration                       |
              A_Procedure_Body_Stub                      |
              A_Function_Body_Stub                       |
              A_Generic_Procedure_Declaration            |
              A_Generic_Function_Declaration             |
              An_Access_To_Procedure                     |
              An_Access_To_Protected_Procedure           |
              An_Access_To_Function                      |
              An_Access_To_Protected_Function            |
              An_Anonymous_Access_To_Procedure           |
              An_Anonymous_Access_To_Protected_Procedure |
              An_Anonymous_Access_To_Function            |
              An_Anonymous_Access_To_Protected_Function  =>

            Ident := 1;

         when others =>
            null;
      end case;

      if Is_First_Parameter_Spec then
         Compute_Parameter_Layout;

         if Par_Spec_On_Separate_Lines then
            PP_New_Line (Adjust_Depth => Ident, Backspace => 1);
         elsif Encl_Kind  /= An_Accept_Statement then
            PP_Continue_Line (No_Space => RM_Style_Spacing);
         end if;

         if Get_Enclosing_Kind /= An_Accept_Statement then
            PP_Delimiter (Left_Parenthesis_Dlm);
            Get_Next_Ada_Lexem;
         end if;

         Is_First_Parameter_Spec := False;

      else

         if Par_Spec_On_Separate_Lines then
            PP_New_Line (Adjust_Depth => Ident);
         end if;

      end if;

   end A_Parameter_Specification_Pre_Op;

   ---------------------------------------
   -- A_Parenthesized_Expression_Pre_Op --
   ---------------------------------------

   procedure A_Parenthesized_Expression_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      Tmp_Pos : Integer;
   begin
      A_General_Expression_Pre_Op (Element, Control, State); --  ???

      PP_Delimiter (Left_Parenthesis_Dlm);
      Tmp_Pos := Output_Pos;
      Get_Next_Ada_Lexem;

      --  In case if we have a comment just after '(', see G202-008
      if Is_New_Output_Line then
         PP_Pad (Tmp_Pos);
      end if;

   end A_Parenthesized_Expression_Pre_Op;

   ---------------------
   -- A_Pragma_Pre_Op --
   ---------------------

   procedure A_Pragma_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      Pragma_Association_Start : constant Positive := 1;
   begin
      PP_New_Line;
      PP_Keyword (KW_Pragma);
      Get_Next_Ada_Lexem;

      PP_Continue_Line;

      PP_Word (Capitalize (Element, PP_Pragma_Casing));

      Get_Next_Ada_Lexem;

      Detect_Delimiter;

      case Delimiter is

         when Left_Parenthesis_Dlm =>

            Compute_Call_Layout (Element);

         when Semicolon_Dlm =>

            if Is_New_Output_Line then
               PP_New_Continuation_Line;
               --  ':' will be set in Post_operation
            end if;

         when others =>
            null;
      end case;

      List_Start_Stack.Push (Pragma_Association_Start);

      Prev_Element := Nil_Element;

   end A_Pragma_Pre_Op;

   --------------------------------------
   -- A_Private_Type_Definition_Pre_Op --
   --------------------------------------

   procedure A_Private_Type_Definition_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      PP_Continue_Line;

      loop
         Detect_Keyword;
         PP_Keyword (Keyword);
         Get_Next_Ada_Lexem;
         exit when Keyword = KW_Private;
         PP_Continue_Line;
      end loop;

   end A_Private_Type_Definition_Pre_Op;

   ------------------------------------
   -- A_Program_Unit_Renaming_Pre_Op --
   ------------------------------------

   procedure A_Program_Unit_Renaming_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      PP_New_Line;
      Detect_Keyword;
      PP_Keyword (Keyword);
      Get_Next_Ada_Lexem;
      Detect_Keyword;

      while Keyword /= Not_A_KW loop
         PP_Continue_Line;
         PP_Keyword (Keyword);
         Get_Next_Ada_Lexem;
         Detect_Keyword;
      end loop;

      Is_First_Parameter_Spec := True;

   end A_Program_Unit_Renaming_Pre_Op;

   ---------------------------------------
   -- A_Program_Unit_Declaration_Pre_Op --
   ---------------------------------------

   procedure A_Program_Unit_Declaration_Pre_Op
     (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);

      Space_Needed : Positive;
      Has_Comments : Boolean;
   begin
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      PP_New_Line;
      Detect_Keyword;
      PP_Keyword (Keyword);
      Get_Next_Ada_Lexem;
      Detect_Keyword;

      while Keyword /= Not_A_KW loop
         PP_Continue_Line;
         PP_Keyword (Keyword);
         Get_Next_Ada_Lexem;
         Detect_Keyword;
      end loop;

      Is_First_Parameter_Spec := True; --  ??? Why it is here?

      if Arg_Kind = A_Formal_Package_Declaration then

         Detect_Possible_Layout
           (The_Element     => Element,
            Space_In_Output => Space_Needed,
            Comment_Inside  => Has_Comments);

         if Space_Needed > Available_In_Output or else
            Has_Comments
         then
            Set_Generic_Associations_On_Separate_Lines;
         end if;

      end if;

   end A_Program_Unit_Declaration_Pre_Op;

   ---------------------------
   -- A_Program_Unit_Pre_Op --
   ---------------------------

   procedure A_Program_Unit_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      KW_Overriding_Allowed : Boolean := False;
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      PP_New_Line;
      Detect_Keyword;

      if Keyword = KW_Not then
         KW_Overriding_Allowed := True;
      end if;

      PP_Keyword (Keyword);
      Get_Next_Ada_Lexem;
      Detect_Keyword;

      while Keyword = KW_Body                                        or else
            Keyword = KW_Type                                        or else
            (Keyword = KW_Overriding and then KW_Overriding_Allowed) or else
            Keyword = KW_Procedure                                   or else
            Keyword = KW_Function                                    or else
            Keyword = KW_Package
      loop
         PP_Continue_Line;
         PP_Keyword (Keyword);
         Get_Next_Ada_Lexem;
         Detect_Keyword;
         KW_Overriding_Allowed := False;
      end loop;

      Increase_Indentation;

      Is_First_Parameter_Spec := True;

   end A_Program_Unit_Pre_Op;

   ----------------------------------------
   -- A_Range_Attribute_Reference_Pre_Op --
   ----------------------------------------

   procedure A_Range_Attribute_Reference_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      Encl_Kind : constant Flat_Element_Kinds := Get_Enclosing_Kind;
   begin

      if Encl_Kind = A_Subtype_Indication or else
         Encl_Kind = A_Discrete_Subtype_Indication_As_Subtype_Definition
      then
         PP_Continue_Line;
         PP_Keyword (KW_Range);
         Get_Next_Ada_Lexem;
         PP_Continue_Line;
      end if;

   end A_Range_Attribute_Reference_Pre_Op;

   --------------------------------
   -- A_Record_Definition_Pre_Op --
   --------------------------------

   procedure A_Record_Definition_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      Detect_Keyword;

      if Keyword = KW_With then
         --  Record extension...

         if Available_In_Output > 5 then
            PP_Space;
         else
            PP_New_Continuation_Line;
         end if;

         PP_Keyword (KW_With);
         Get_Next_Ada_Lexem;
      end if;

      if not Compact_Layout then
         Increase_Indentation;
      end if;

      if Is_New_Output_Line or else not Compact_Layout then
         PP_New_Line;
      else

         if Available_In_Output > 6 and then
            Current_Out_Line = Last_Type_Start
         then
            PP_Space;
         else

            if Compact_Layout then
               Increase_Indentation;
               Set_Impose_Extra_Indentation;
            end if;

            PP_New_Line;
         end if;

      end if;

      PP_Keyword (KW_Record);

      Get_Next_Ada_Lexem;

      Increase_Indentation;

   end A_Record_Definition_Pre_Op;

   -------------------------------------
   -- A_Record_Type_Definition_Pre_Op --
   -------------------------------------

   procedure A_Record_Type_Definition_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      --  here we may have [[abstract] tagged] [limited] record
      --  null record definition is processed separately

      Detect_Keyword;

      while not (Keyword = KW_Record or else
                 Keyword = KW_Null)
      loop
         PP_Continue_Line;
         PP_Keyword (Keyword);
         Get_Next_Ada_Lexem;
         Detect_Keyword;
      end loop;

   end A_Record_Type_Definition_Pre_Op;

   ------------------------------------
   -- A_Representation_Clause_Pre_Op --
   ------------------------------------

   procedure A_Representation_Clause_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      PP_New_Line;
      PP_Keyword (KW_For);
      Get_Next_Ada_Lexem;
      PP_Continue_Line;
   end A_Representation_Clause_Pre_Op;

   --------------------------
   -- A_Select_Path_Pre_Op --
   --------------------------

   procedure A_Select_Path_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      if Flat_Element_Kind (Element) = An_Or_Path then
         PP_New_Line;
         PP_Keyword (KW_Or);
         Get_Next_Ada_Lexem;
      end if;

      Detect_Keyword;

      if Keyword = KW_When then
         PP_Continue_Line;
         PP_Keyword (KW_When);
         Get_Next_Ada_Lexem;
         PP_Continue_Line;
      end if;

      Increase_Indentation;

   end A_Select_Path_Pre_Op;

   ---------------------------------------------
   -- A_Signed_Integer_Type_Definition_Pre_Op --
   ---------------------------------------------

   procedure A_Signed_Integer_Type_Definition_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      null; --  ??? Nothing_To_Do???
   end A_Signed_Integer_Type_Definition_Pre_Op;

   --------------------------------------
   -- A_Simple_Expression_Range_Pre_Op --
   --------------------------------------

   procedure A_Simple_Expression_Range_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      Encl_Kind : constant Flat_Element_Kinds := Get_Enclosing_Kind;
   begin

      PP_Continue_Line_Postponed;

      case Encl_Kind is
         when A_Subtype_Indication             |
              A_Signed_Integer_Type_Definition |
              A_Floating_Point_Definition ..
              A_Decimal_Fixed_Point_Definition |
              A_Discrete_Subtype_Indication_As_Subtype_Definition =>

            if Available_In_Output < 7 then
               PP_New_Continuation_Line;
            else
               PP_Postponed_Space;
            end if;

            PP_Keyword (KW_Range);
            Get_Next_Ada_Lexem;
            PP_Continue_Line_Postponed;
         when others =>
            null;
      end case;

      Compute_Simple_Expression_Range_Layout (Element);

   end A_Simple_Expression_Range_Pre_Op;

   ---------------------------------
   -- A_Subtype_Indication_Pre_Op --
   ---------------------------------

   procedure A_Subtype_Indication_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      --  In Ada 2005 we may have null exclusion:

      Detect_Keyword;

      while Keyword /= Not_A_KW loop
         PP_Continue_Line;
         PP_Keyword (Keyword);
         Get_Next_Ada_Lexem;
         Detect_Keyword;
      end loop;

      case Get_Enclosing_Kind is

         when A_Record_Component_Association ..
              An_Array_Component_Association    |
              A_Case_Path                       |
              A_Variant =>
            null;
         when others =>
            PP_Continue_Line_Postponed;
      end case;

   end A_Subtype_Indication_Pre_Op;

   ------------------------------
   -- A_Then_Abort_Path_Pre_Op --
   ------------------------------

   procedure A_Then_Abort_Path_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      PP_New_Line;
      PP_Keyword (KW_Then);
      Get_Next_Ada_Lexem;
      Detect_Keyword;
      PP_Continue_Line;
      PP_Keyword (KW_Abort);
      Increase_Indentation;

      Get_Next_Ada_Lexem;

   end A_Then_Abort_Path_Pre_Op;

   -------------------------
   -- A_Use_Clause_Pre_Op --
   -------------------------

   procedure A_Use_Clause_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      Space_Needed : Positive;
      Has_Comments : Boolean;

      Starts_From_New_Line : Boolean := False;

   begin

      if In_Context_Clause
       and then
         not Separate_Line_For_USE
       and then
        (not Is_New_Output_Line)
       and then
         Share_Prefix (Element)
      then
         --  If we are in the context clause, we try to place the use clause
         --  in the same line as the immediately preceding with clause (if
         --  any). At the moment, we do not check that the use clause contains
         --  the same name which are given in this with clause but probably we
         --  should.

         Detect_Possible_Layout
           (The_Element     => Element,
            Space_In_Output => Space_Needed,
            Comment_Inside  => Has_Comments);

         if not Has_Comments and then
            Space_Needed + 1 <= Available_In_Output
         then

            if Prev_Element_Kind = A_With_Clause
              and then
               Use_In_Paragraph > 0
            then
               PP_Pad_Up_To (Use_In_Paragraph);
            else
               PP_Continue_Line;
            end if;
         else
            PP_New_Line;
            Starts_From_New_Line := True;
         end if;

      else
         PP_New_Line;
         Starts_From_New_Line := True;
      end if;

      PP_Keyword (KW_Use);

      if In_Context_Clause
       and then
         Prev_Element_Kind = A_With_Clause
       and then
         Flat_Element_Kind (Element) = A_Use_Package_Clause
       and then
         Starts_From_New_Line
      then
         PP_Pad (3);
      end if;

      List_Start_Stack.Push (Output_Pos - 3 + PP_Indentation  - 1);
      Get_Next_Ada_Lexem;
      PP_Continue_Line;

      case Flat_Element_Kind (Element) is
         when A_Use_Package_Clause =>
            null;

         when A_Use_Type_Clause =>
            PP_Keyword (KW_Type);
            Get_Next_Ada_Lexem;
            PP_Continue_Line;

         when A_Use_All_Type_Clause =>
            PP_Keyword (KW_All);
            Get_Next_Ada_Lexem;
            PP_Space;
            PP_Keyword (KW_Type);
            Get_Next_Ada_Lexem;
            PP_Continue_Line;

         when others =>
            raise Program_Error;
      end case;

      Prev_Element_Kind := Flat_Element_Kind (Element);

   end A_Use_Clause_Pre_Op;

   --------------------------
   -- A_With_Clause_Pre_Op --
   --------------------------

   procedure A_With_Clause_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      Restore_In_Paragraph : constant Boolean := In_Paragraph;
   begin
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      PP_New_Line;
      Detect_Keyword;

      while Keyword = KW_Private or else
            Keyword = KW_Limited or else
            Keyword = KW_With
      loop
         PP_Keyword (Keyword);
         Get_Next_Ada_Lexem;
         Detect_Keyword;
         PP_Continue_Line;
      end loop;

      In_Paragraph      := Restore_In_Paragraph;
      Prev_Element_Kind := A_With_Clause;

      Set_Prev_Element (Element);

   end A_With_Clause_Pre_Op;

   ------------------------------------
   -- An_Access_To_Subprogram_Pre_Op --
   ------------------------------------

   procedure An_Access_To_Subprogram_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State) is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      Detect_Keyword;

      while Keyword /= Not_A_KW loop
         PP_Continue_Line;
         PP_Keyword (Keyword);
         Get_Next_Ada_Lexem;
         Detect_Keyword;
      end loop;

      Is_First_Parameter_Spec := True;

   end An_Access_To_Subprogram_Pre_Op;

   --------------------------------------
   -- An_Access_Type_Definition_Pre_Op --
   --------------------------------------

   procedure An_Access_Type_Definition_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      PP_Continue_Line;
      Detect_Keyword;
      PP_Keyword (Keyword);
      Get_Next_Ada_Lexem;
      Detect_Keyword;

      while Keyword /= Not_A_KW loop
         PP_Continue_Line;
         PP_Keyword (Keyword);
         Get_Next_Ada_Lexem;
         Detect_Keyword;
      end loop;

   end An_Access_Type_Definition_Pre_Op;

   ------------------------------------------------
   -- An_Anonymous_Access_Type_Definition_Pre_Op --
   ------------------------------------------------

   procedure An_Anonymous_Access_Type_Definition_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      An_Access_Type_Definition_Pre_Op (Element, Control, State);
      PP_Continue_Line_Postponed;
   end An_Anonymous_Access_Type_Definition_Pre_Op;

   -------------------------
   -- An_Aggregate_Pre_Op --
   -------------------------

   procedure An_Aggregate_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin

      if A4G.Skip_TB.Needs_Extra_Parentheses (Element) then
         A_General_Expression_Pre_Op (Element, Control, State);
      end if;

      Compute_Aggregate_Layout (Element);

--        if Keep_Huge_Aggregates_As_Is
--          and then
--           Is_Huge_Aggregate (Element)
--          and then
--           Starts_From_New_Line (Element)
--        then
--           Print_As_Is (Element);
--
--           GNATPP.Post_Operations.An_Expression_Post_Op
--             (Element, Control, State);
--
--           Control := Abandon_Children;
--           return;
--        end if;

      if Is_New_Output_Line or else
         Start_Aggregate_From_New_Line
      then
         PP_New_Line (Adjust_Depth => 1, Backspace => 1);
      elsif Flat_Element_Kind (Element) = A_Discriminant_Constraint
         and then
            not RM_Style_Spacing
      then
         PP_Space;
      else
         PP_Postponed_Space;
      end if;

      PP_Delimiter (Left_Parenthesis_Dlm);

      Get_Next_Ada_Lexem;

      if Is_New_Output_Line then
         PP_New_Continuation_Line;
      end if;

      --  Processing for   '(null record);'   case

      if Flat_Element_Kind (Element) = A_Record_Aggregate
        and then
         Is_Nil (Record_Component_Associations (Element))
      then

         Detect_Keyword;

         if Keyword = KW_Null then
            PP_Keyword (KW_Null);
            Get_Next_Ada_Lexem;

            if Available_In_Output < 9 then
               PP_New_Continuation_Line;
            else
               PP_Space;
            end if;

            PP_Keyword (KW_Record);

            Get_Next_Ada_Lexem;
            PP_Delimiter (Right_Parenthesis_Dlm);
         end if;

      end if;

   end An_Aggregate_Pre_Op;

   --------------------------
   -- An_Allocation_Pre_Op --
   --------------------------

   procedure An_Allocation_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      A_General_Expression_Pre_Op (Element, Control, State);

      PP_Continue_Line_Postponed;

      PP_Keyword (KW_New);

      Get_Next_Ada_Lexem;

      PP_Continue_Line_Postponed;

   end An_Allocation_Pre_Op;

   --------------------------------
   -- An_Array_Definition_Pre_Op --
   --------------------------------

   procedure An_Array_Definition_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      Compute_Array_Definition_Layout (Element);

      if Start_Array_Def_From_New_Line or else
         Is_New_Output_Line
      then
         PP_New_Continuation_Line;
      else
         PP_Space; --  ???
      end if;

      PP_Keyword (KW_Array);

      Get_Next_Ada_Lexem;

      if Is_New_Output_Line then

         if Start_Index_Def_From_New_Line then
            PP_New_Line_For_Index_Def;
         else
            PP_New_Continuation_Line;
         end if;
      elsif not RM_Style_Spacing then
         PP_Space; --  ???
      end if;

      PP_Delimiter (Left_Parenthesis_Dlm);

      Get_Next_Ada_Lexem;

   end An_Array_Definition_Pre_Op;

   ---------------------------
   -- An_Association_Pre_Op --
   ---------------------------

   procedure An_Association_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      Arg_Kind  : constant Flat_Element_Kinds := Flat_Element_Kind (Element);
      Pad_Up_To : Natural                     := 0;

      Is_Pref_Call                  : Boolean;
      Is_First_Parameter_Asociation : Boolean;

      Op_Kind : Flat_Element_Kinds := Not_An_Element;

      Tmp_El    : Asis.Element;
      Tmp_Space : Natural := 0;
      Tmp_Pos   : Natural;
      Tmp_Bool  : Boolean;
      pragma Warnings (Off, Tmp_Bool);
      --  Next_Space is used as placeholder parameter in the call to
      --  Detect_Possible_Layout

      Old_Current_Line     : Asis.Text.Line_Number := 0;  --   ???
      Do_Not_Need_New_Line : Boolean               := False;
   begin
      --  Some more sophisticated computation of the association layout
      --  is needed

      case Arg_Kind is
         when A_Generic_Association =>

            Is_First_Parameter_Asociation := Is_First_Association (Element);

            if Generic_Associations_On_Separate_Lines then

               if Is_First_Parameter_Asociation then

                  if Available_In_Output >= 2
                    and then
                     not RM_Style_Spacing
                  then
                     PP_Space;
                  else
                     PP_New_Continuation_Line;
                     Do_Not_Need_New_Line := True;
                  end if;

                  PP_Delimiter (Left_Parenthesis_Dlm);
                  Old_Current_Line := Current_Line;
                  Get_Next_Ada_Lexem;

                  if RM_Style_Spacing
                    and then
                     (Do_Not_Need_New_Line
                     or else
                      Old_Current_Line = Current_Line)
                  then
                     null;
                  elsif Is_New_Output_Line then
                     PP_Pad (PP_Indentation);
                  else
                     PP_New_Line (Adjust_Depth => 1);
                  end if;

                  if Align_Arrows then
                     Compute_Generic_Actuals_Layout;
                  end if;

               else
                  PP_New_Line (Adjust_Depth => 1);
               end if;

            else
               PP_Continue_Line;

               if Is_First_Parameter_Asociation then
                  PP_Continue_Line (No_Space => RM_Style_Spacing);
                  PP_Delimiter (Left_Parenthesis_Dlm);
                  Get_Next_Ada_Lexem;
               else
                  PP_Continue_Line;
               end if;

            end if;

         when A_Record_Component_Association |
              An_Array_Component_Association |
              A_Discriminant_Association     =>

            if Comp_Asctns_On_Sep_Lines and then
               Last_Dlm /= Left_Parenthesis_Dlm
            then
               PP_New_Line (Adjust_Depth => 1);
               PP_Pad_Up_To (Comp_Asctns_Start_Pos);
            end if;

            Compute_Case_Choices_Layout (Element);

         when A_Parameter_Association       |
              A_Pragma_Argument_Association =>

            if Is_First_Prefix_Notation_Parameter (Element) then
               Control := Abandon_Children;
               return;
            end if;

            Is_Pref_Call :=
               Get_Enclosing_Kind /= A_Function_Call or else
               Is_Prefix_Call (Get_Enclosing_Element);

            if not Is_Pref_Call and then
               Get_Enclosing_Kind = A_Function_Call
            then
               Op_Kind := Flat_Element_Kind (Prefix (Get_Enclosing_Element));
            end if;

            Is_First_Parameter_Asociation := Is_First_Association (Element);
            --  ??? This should be a general check for all forms of
            --  ???  associations

            if Pars_On_Sep_Lines then

               Pad_Up_To := Start_Par_Pos;

               if Is_First_Parameter_Asociation and then Is_Pref_Call then
                  Pad_Up_To := Pad_Up_To - 1;
               end if;

               if not (Is_First_Parameter_Asociation and then
                       not Is_Pref_Call)
               then

                  Tmp_El := Formal_Parameter (Element);

                  if Is_Nil (Tmp_El) then
                     Tmp_El := Actual_Parameter (Element);
                  end if;

                  if Is_Terminal_Element (Tmp_El) then
                     Detect_Possible_Layout
                       (The_Element     => Tmp_El,
                        Space_In_Output => Tmp_Space,
                        Comment_Inside  => Tmp_Bool);
                  end if;

                  if Pad_Up_To + Tmp_Space <= Max_Line_Length then
                     PP_New_Line_And_Pad (Up_To => Pad_Up_To);
                  elsif not Is_First_Parameter_Asociation and then
                        Output_Pos + 2 <= Max_Line_Length
                  then
                     PP_Space;
                  end if;

               end if;

            elsif not (Last_Dlm = Left_Parenthesis_Dlm   or else
                       Op_Kind in A_Unary_Plus_Operator ..
                                  A_Unary_Minus_Operator or else
                       ((Last_Dlm = Minus_Dlm or else Last_Dlm = Plus_Dlm)
                         and then Unary_Adding_Op_Just_Printed))
            then
               if Arg_Kind = A_Parameter_Association then
                  Tmp_El := Get_Enclosing_Element;

                  if Flat_Element_Kind (Tmp_El) = A_Function_Call
                    and then
                     not Is_Prefix_Call (Tmp_El)
                  then
                     Tmp_El := Prefix (Tmp_El);

--                     case Operator_Kind (Tmp_El) is
--                        when A_Not_Operator  =>
                           PP_Continue_Line;
--                        when others =>
--                           PP_Continue_Line (No_Space => RM_Style_Spacing);
--                           --  ???
--                     end case;
                  else
                     PP_Continue_Line (No_Space => RM_Style_Spacing); --  ???
                  end if;
               else
                  PP_Continue_Line (No_Space => RM_Style_Spacing); --  ???
               end if;
            end if;

            if Is_First_Parameter_Asociation then
               Set_Is_First_Par_Association;

               if Is_Pref_Call then
                  PP_Delimiter (Left_Parenthesis_Dlm);
                  Tmp_Pos := Get_Output_Pos;

                  Get_Next_Ada_Lexem;

                  if Is_New_Output_Line then
                     PP_New_Line_And_Pad (Up_To => Tmp_Pos);
                  end if;

               end if;

            end if;

         when others =>
            --  Temporary solution ???
            return;
      end case;

      --  Storing the alignment info from the enclosing element
      --  Set_Current_Arrow_Start_Pos (Arrow_Start_Pos);

   end An_Association_Pre_Op;

   -----------------------------------------
   -- An_Entry_Index_Specification_Pre_Op --
   -----------------------------------------

   procedure  An_Entry_Index_Specification_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      PP_Continue_Line (No_Space => RM_Style_Spacing);
      PP_Delimiter (Left_Parenthesis_Dlm);
      Get_Next_Ada_Lexem;
      PP_Keyword (KW_For);
      Get_Next_Ada_Lexem;
   end An_Entry_Index_Specification_Pre_Op;

   -------------------------------------------
   -- An_Enumeration_Type_Definition_Pre_Op --
   -------------------------------------------

   procedure An_Enumeration_Type_Definition_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      Compute_Enum_Def_Layout (Element);

      PP_Continue_Line;

      PP_Delimiter (Left_Parenthesis_Dlm);

      Get_Next_Ada_Lexem;

   end An_Enumeration_Type_Definition_Pre_Op;

   ------------------------------
   -- An_Exit_Statement_Pre_Op --
   ------------------------------

   procedure An_Exit_Statement_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      Loop_Name : Asis.Element;
   begin
      PP_New_Line;
      PP_Labels (Element);
      PP_Keyword (KW_Exit);
      Get_Next_Ada_Lexem;

      Loop_Name := Exit_Loop_Name (Element);

      if Is_Nil (Loop_Name) and then End_Labels then
         Loop_Name := Corresponding_Loop_Exited (Element);
         Loop_Name := Statement_Identifier (Loop_Name);

         if not Is_Nil (Loop_Name) then
            PP_Continue_Line;

            PP_Word_No_Move (Capitalize (Loop_Name, PP_Name_Casing));

         end if;

      end if;

      Detect_Delimiter;

      if Delimiter = Not_A_Dlm then
         --  we have 'exit Loop_Name;' or
         --  we have 'exit when Condition;'
         PP_Continue_Line;

         Detect_Keyword;

         if Keyword = KW_When then
            PP_Keyword (Keyword);
            Get_Next_Ada_Lexem;
            PP_Continue_Line;
         end if;

      end if;

   end An_Exit_Statement_Pre_Op;

   -----------------------------
   -- An_Expanded_Name_Pre_Op --
   -----------------------------

   procedure An_Expanded_Name_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      Enclosing_El_Kind : Flat_Element_Kinds;
      Space_Needed : Positive;
      Has_Comments : Boolean;
      pragma Warnings (Off, Has_Comments);
      --  Next_Space is used as placeholder parameter in the call to
      --  Detect_Possible_Layout

   begin
      Enclosing_El_Kind := Get_Enclosing_Kind;

      Detect_Possible_Layout
        (The_Element     => Element,
         Space_In_Output => Space_Needed,
         Comment_Inside  => Has_Comments);

      if Is_New_Output_Line or else
         Space_Needed + 1 > Available_In_Output
      then

         --  ???

         if not (Enclosing_El_Kind =  A_Procedure_Call_Statement or else
                 Enclosing_El_Kind =  An_Entry_Call_Statement    or else
                 Enclosing_El_Kind =  An_Assignment_Statement    or else
                 Enclosing_El_Kind in Flat_Association_Kinds    or else
                 Enclosing_El_Kind =  A_Selected_Component)
         then
            PP_New_Continuation_Line;
         end if;

      elsif Flat_Element_Kind (Element) = A_Defining_Expanded_Name then
         PP_Continue_Line_Postponed;
      end if;

      A_General_Expression_Pre_Op (Element, Control, State);

   end An_Expanded_Name_Pre_Op;

   --------------------------
   -- An_Identifier_Pre_Op --
   --------------------------

   procedure An_Identifier_Pre_Op
     (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);
      Name     : Asis.Element                := Element;
      --  This Element should be set to the corresponding defining name if
      --  for references As_Declared casing scheme is set

      Casing              : PP_Casing := PP_Name_Casing;
      Enclosing_El_Kind   : Flat_Element_Kinds;
      Needed_Len          : Positive :=
         Current_State.The_Span.Last_Column -
         Current_State.The_Span.First_Column + 1 + 1;
      --  Second "+ 1" means that usually any identifier is followed by
      --  some delimiter
   begin

      --  Defining the position to output the identifier from:

      if not Is_New_Output_Line then

         if Last_Dlm = Comma_Dlm then
            Needed_Len := Needed_Len + 1;
         end if;

         if Needed_Len > Available_In_Output then
            PP_New_Continuation_Line;
         elsif (Last_KW = KW_Return
             and then
                not In_Return_Statement (Element))
           or else
            Last_KW = KW_Null --  null exclusion in function result
         then
            PP_Space;
         end if;

      end if;

      A_General_Expression_Pre_Op (Element, Control, State);

      if Arg_Kind = A_Character_Literal then
         PP_Word (Line_Buf
           (Current_State.The_Span.First_Column ..
            Current_State.The_Span.Last_Column));

      elsif Arg_Kind in Flat_Operator_Symbol_Kinds then
         PP_Word (Capitalize_Image (Line_Buf
                    (Current_State.The_Span.First_Column ..
                     Current_State.The_Span.Last_Column), PP_Keyword_Casing));
      else

         Name              := Unique_Name_Definition (Element);
         Enclosing_El_Kind := Get_Enclosing_Kind;

         if Is_Nil (Name) then

            --  We have to output the reference in the same casing as the
            --  corresponding declaration, but we do not have a declaration!

            Name := Element;
            --  Back to the reference if we do not have the declaration

            case Enclosing_El_Kind is
               when Flat_Pragma_Kinds | A_Pragma_Argument_Association =>
                  Casing := PP_Pragma_Casing;
               when Flat_Attribute_Reference_Kinds =>
                  Casing := PP_Attribute_Casing;
               when others =>
                  Casing := PP_Name_Casing;
            end case;

         elsif Flat_Element_Kind (Name) =
               A_Defining_Enumeration_Literal
         then
            Casing := PP_Enum_Literal_Casing;
         else
            case Flat_Element_Kind (Enclosing_Element (Name)) is
               when A_Subtype_Declaration                |
                    An_Ordinary_Type_Declaration         |
                    A_Task_Type_Declaration              |
                    A_Protected_Type_Declaration         |
                    An_Incomplete_Type_Declaration       |
                    A_Tagged_Incomplete_Type_Declaration |
                    A_Private_Type_Declaration           |
                    A_Private_Extension_Declaration      |
                    A_Formal_Type_Declaration            |
                    A_Formal_Incomplete_Type_Declaration =>
                  Casing := PP_Type_Casing;
               when An_Integer_Number_Declaration |
                    A_Real_Number_Declaration     =>
                  Casing := PP_Nnumbers_Casing;
               when others => null;
            end case;
         end if;

         PP_Word (Capitalize (Name, Casing));

      end if;

      Get_Next_Ada_Lexem;

   end An_Identifier_Pre_Op;

   --------------------------------
   -- An_Index_Constraint_Pre_Op --
   --------------------------------

   procedure An_Index_Constraint_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      List_Start_Stack.Push (Output_Pos);
      Get_Next_Ada_Lexem;

      if Is_New_Output_Line then
         PP_Pad (List_Start_Stack.Top);
      end if;

   end An_Index_Constraint_Pre_Op;

   -----------------------
   -- An_If_Path_Pre_Op --
   -----------------------

   procedure An_If_Path_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      Arg_Kind : constant Flat_Element_Kinds := Flat_Element_Kind (Element);
   begin

      if Arg_Kind /= An_If_Path then
         PP_New_Line;
      end if;

      Detect_Keyword;

      if Keyword = KW_Elsif or else
         Keyword = KW_Else
      then
         PP_Keyword (Keyword);

         if Keyword = KW_Else then
            Increase_Indentation;
         end if;

         Get_Next_Ada_Lexem;

         if Keyword = KW_Elsif then
            PP_Continue_Line;
         end if;

      end if;

      if Keyword /= KW_Else then
         Increase_Indentation;
      end if;

   end An_If_Path_Pre_Op;

   -----------------------------
   -- An_Instantiation_Pre_Op --
   -----------------------------

   procedure An_Instantiation_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      Space_Needed : Positive;
      Has_Comments : Boolean;
   begin

      PP_New_Line;

      --  Computing the layout information is too primitive...

      Detect_Possible_Layout
        (The_Element     => Element,
         Space_In_Output => Space_Needed,
         Comment_Inside  => Has_Comments);

      if Space_Needed > Available_In_Output or else
         Has_Comments
      then
         Set_Generic_Associations_On_Separate_Lines;
      end if;

      Detect_Keyword;
      PP_Keyword (Keyword);
      Get_Next_Ada_Lexem;
      Detect_Keyword;

      while Keyword /= Not_A_KW loop
         PP_Continue_Line;
         PP_Keyword (Keyword);
         Get_Next_Ada_Lexem;
         Detect_Keyword;
      end loop;

   end An_Instantiation_Pre_Op;

   ------------------------------------
   -- An_Interface_Definition_Pre_Op --
   ------------------------------------

   procedure An_Interface_Definition_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin

      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      PP_Continue_Line;
      Detect_Keyword;
      PP_Keyword (Keyword);
      Get_Next_Ada_Lexem;
      Detect_Keyword;

      while Keyword /= Not_A_KW loop
         PP_Continue_Line;
         PP_Keyword (Keyword);
         Get_Next_Ada_Lexem;
         Detect_Keyword;
      end loop;

   end An_Interface_Definition_Pre_Op;

   ----------------------------------
   -- An_Object_Declaration_Pre_Op --
   ----------------------------------

   procedure An_Object_Declaration_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      Arg_Kind  : constant Flat_Element_Kinds := Flat_Element_Kind (Element);
   begin
      PP_New_Line;

      case Arg_Kind is
         when  A_Variable_Declaration          |
               A_Constant_Declaration          |
               A_Deferred_Constant_Declaration =>

            Compute_Obj_Decl_Layout (Element);

         when others =>
            null;
      end case;
   end An_Object_Declaration_Pre_Op;

   ------------------------
   -- An_Operator_Pre_Op --
   ------------------------

   procedure An_Operator_Pre_Op
     (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);
      Encl_Kind : constant Flat_Element_Kinds := Get_Enclosing_Kind;
      Is_Pref_Call : constant Boolean :=
        Is_Prefix_Call (Get_Enclosing_Element);
   begin

      if not (Arg_Kind in Flat_Operator_Symbol_Kinds and then
              not Is_Unary (Arg_Kind)                and then
              Encl_Kind = A_Function_Call   and then
              not Is_Pref_Call)
      then

         if not ((Is_Unary (Arg_Kind) and then
                  Last_Dlm = Left_Parenthesis_Dlm)
               or else
                  Encl_Kind = A_Pragma_Argument_Association
               or else
                  Get_Enclosing_Kind = A_Selected_Component)
         then
            PP_Continue_Line; --  ???
         end if;

         if Get_Enclosing_Kind = A_Function_Call and then
            not Is_Pref_Call                     and then
            Is_Unary (Arg_Kind)
         then
            PP_Operator (Arg_Kind);
            Get_Next_Ada_Lexem;

            if Arg_Kind not in A_Unary_Plus_Operator ..
                               A_Unary_Minus_Operator
            then
               PP_Continue_Line_Postponed;
            end if;

         else
            An_Identifier_Pre_Op (Element, Control, State);
         end if;

      end if;

   end An_Operator_Pre_Op;

   -----------------------------------------
   -- An_Ordinary_Type_Declaration_Pre_Op --
   -----------------------------------------

   procedure An_Ordinary_Type_Declaration_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      PP_New_Line;
      Detect_Keyword;
      PP_Keyword (Keyword);
      Get_Next_Ada_Lexem;
   end An_Ordinary_Type_Declaration_Pre_Op;

   -----------------------------
   -- An_Others_Choice_Pre_Op --
   -----------------------------

   procedure An_Others_Choice_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      PP_Postponed_Space;
      PP_Keyword (KW_Others);
      Get_Next_Ada_Lexem;
      PP_Continue_Line;
      PP_Delimiter (Arrow_Dlm);
      Get_Next_Ada_Lexem;

      if Get_Enclosing_Kind in A_Record_Component_Association ..
                               A_Generic_Association
      then
         PP_Continue_Line;

         Detect_Delimiter;

         if Delimiter = Box_Dlm then
            PP_Delimiter (Box_Dlm);
            Get_Next_Ada_Lexem;
         end if;

      end if;

   end An_Others_Choice_Pre_Op;

   -----------------------------------------
   -- An_Unknown_Discriminant_Part_Pre_Op --
   -----------------------------------------

   procedure An_Unknown_Discriminant_Part_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (Element);
      pragma Unreferenced (Control);
      pragma Unreferenced (State);

      if not  RM_Style_Spacing then
         PP_Space;
      end if;

      PP_Delimiter (Left_Parenthesis_Dlm);
      Get_Next_Ada_Lexem;

      if Is_New_Output_Line then
         PP_New_Continuation_Line;
      end if;

      PP_Delimiter (Box_Dlm);
      Get_Next_Ada_Lexem;

      if Is_New_Output_Line then
         PP_New_Continuation_Line;
      end if;

--      PP_Delimiter (Right_Parenthesis_Dlm);
--      Get_Next_Ada_Lexem;

   end An_Unknown_Discriminant_Part_Pre_Op;

   ---------------
   -- PP_Labels --
   ---------------

   procedure PP_Labels (Statement : Asis.Element) is
   begin

      if Flat_Element_Kind (Statement) not in Flat_Statement_Kinds then
         --  Pre-Ops for statements may be used for non-statement elements
         return;
      end if;

      declare
         Labels           : constant Element_List := Label_Names  (Statement);
         Next_Label_Space : Natural;
         Comments_Inside  : Boolean;
         pragma Warnings (Off, Comments_Inside);
      --  Next_Space is used as placeholder parameter in the call to
      --  Detect_Possible_Layout

      begin

         for J in Labels'Range loop
            --  If we are here, Line_Pos points to the first '<' in "<<"
            PP_Delimiter (Left_Label_Bracket_Dlm);
            Get_Next_Ada_Lexem;
            Set_Word_End; --  ??? Do we need this now?

            PP_Word (Capitalize (Labels (J), PP_Name_Casing));

            Get_Next_Ada_Lexem;
            PP_Delimiter (Right_Label_Bracket_Dlm);
            Get_Next_Ada_Lexem;

            if Is_New_Output_Line then
               PP_New_Line;
            elsif J < Labels'Last then
               Detect_Possible_Layout
                 (The_Element     => Labels (J + 1),
                  Space_In_Output => Next_Label_Space,
                  Comment_Inside  => Comments_Inside);

               if Output_Pos + 1 + Next_Label_Space + 4 > Max_Line_Length then
                  PP_New_Line;
               else
                  PP_Space;
               end if;

            end if;

         end loop;

         if Labels /= Nil_Element_List then
            --  We have just printed labels, and now we have to decide if
            --  we should start the statement from the new line

            if Separate_Line_For_Label then
               PP_New_Line;
            else
               Detect_Possible_Layout
                 (The_Element     => Statement,
                  Space_In_Output => Next_Label_Space,
                  Comment_Inside  => Comments_Inside);

               if Next_Label_Space <= Available_In_Output - 1 then
                  PP_Space;
               else
                  PP_New_Line;
               end if;

            end if;

         end if;

      end;
   end PP_Labels;

   ------------------
   -- Share_Prefix --
   ------------------

   function Share_Prefix (Use_Clause : Asis.Element) return Boolean is
      Result  : Boolean := False;
      First_Use_Name : List_Index;
      Last_Use_Name  : List_Index;
      With_Name      : List_Index;
   begin

      if not Is_Nil (Prev_Element) then

         Result := True;

         declare
            Withed_Name_Decomp : constant Asis.Element_List :=
               Decompose_Selected_Component (Prev_Element);

            Used_Names : constant Asis.Element_List :=
              Clause_Names (Use_Clause);

            Used_Name_Decomp : Element_List_Access;
         begin

            Check_Names_From_Use_Clause : for J in Used_Names'Range loop
               Free (Used_Name_Decomp);
               Used_Name_Decomp := new Element_List'
                 (Decompose_Selected_Component (Used_Names (J)));

               First_Use_Name := Used_Name_Decomp'First;
               Last_Use_Name  := Used_Name_Decomp'Last;

               if Clause_Kind (Use_Clause) = A_Use_Type_Clause then
                  --  We do not care about the type name
                  Last_Use_Name := Last_Use_Name - 1;
               end if;

               if Last_Use_Name -  First_Use_Name + 1 >
                  Withed_Name_Decomp'Length
               then
                  Result := False;
                  exit Check_Names_From_Use_Clause;
               end if;

               With_Name := Withed_Name_Decomp'First;

               for K in First_Use_Name .. Last_Use_Name loop

                  if not Is_Equal
                   (Corresponding_Name_Definition
                     (Withed_Name_Decomp (With_Name)),
                    Corresponding_Name_Definition (Used_Name_Decomp (K)))
                  then
                     Result := False;
                     exit Check_Names_From_Use_Clause;
                  end if;

                  With_Name := With_Name + 1;

               end loop;

            end loop Check_Names_From_Use_Clause;

            if not Result then
               Prev_Element := Nil_Element;
            end if;

         end;

      end if;

      return Result;
   end Share_Prefix;

   --  Ada 2012:

   --  ???For now, we print most Ada 2012 features as they are in the source
   --  code. This will be improved later, but at least we'll no longer blow up.

   -------------------------------------------------
   -- A_Generalized_Iterator_Specification_Pre_Op --
   -------------------------------------------------

   procedure A_Generalized_Iterator_Specification_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (State);

      Print_Rest_As_Is (Element);
      Control := Terminate_Immediately;
   end A_Generalized_Iterator_Specification_Pre_Op;

   ----------------------------------------------
   -- An_Element_Iterator_Specification_Pre_Op --
   ----------------------------------------------

   procedure An_Element_Iterator_Specification_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (State);

      Print_Rest_As_Is (Element);
      Control := Terminate_Immediately;
   end An_Element_Iterator_Specification_Pre_Op;

   -----------------------------------------------
   -- An_Expression_Function_Declaration_Pre_Op --
   -----------------------------------------------

   procedure An_Expression_Function_Declaration_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (State);

      Print_Rest_As_Is (Element);
      Control := Terminate_Immediately;
   end An_Expression_Function_Declaration_Pre_Op;

   -------------------------------------------------
   -- A_Formal_Incomplete_Type_Declaration_Pre_Op --
   -------------------------------------------------

   procedure A_Formal_Incomplete_Type_Declaration_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (State);

      Print_Rest_As_Is (Element);
      Control := Terminate_Immediately;
   end A_Formal_Incomplete_Type_Declaration_Pre_Op;

   ------------------------------------
   -- An_Aspect_Specification_Pre_Op --
   ------------------------------------

   procedure An_Aspect_Specification_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (State);

      Print_Rest_As_Is (Element);
      Control := Terminate_Immediately;
   end An_Aspect_Specification_Pre_Op;

   ------------------------------
   -- A_Case_Expression_Pre_Op --
   ------------------------------

   procedure A_Case_Expression_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (State);

      Print_As_Is (Element);
      Control := Abandon_Children;
   end A_Case_Expression_Pre_Op;

   -----------------------------
   -- An_If_Expression_Pre_Op --
   -----------------------------

   procedure An_If_Expression_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (State);

      Print_As_Is (Element);
      Control := Abandon_Children;
   end An_If_Expression_Pre_Op;

   --------------------------------------------
   -- A_For_All_Quantified_Expression_Pre_Op --
   --------------------------------------------

   procedure A_For_All_Quantified_Expression_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (State);

      Print_Rest_As_Is (Element);
      Control := Terminate_Immediately;
   end A_For_All_Quantified_Expression_Pre_Op;

   ---------------------------------------------
   -- A_For_Some_Quantified_Expression_Pre_Op --
   ---------------------------------------------

   procedure A_For_Some_Quantified_Expression_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (State);

      Print_Rest_As_Is (Element);
      Control := Terminate_Immediately;
   end A_For_Some_Quantified_Expression_Pre_Op;

   -----------------------------------
   -- A_Case_Expression_Path_Pre_Op --
   -----------------------------------

   procedure A_Case_Expression_Path_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (State);

      Print_Rest_As_Is (Element);
      Control := Terminate_Immediately;
   end A_Case_Expression_Path_Pre_Op;

   ----------------------------------
   -- An_If_Expression_Path_Pre_Op --
   ----------------------------------

   procedure An_If_Expression_Path_Pre_Op
     (Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Source_Traversal_State)
   is
   begin
      pragma Unreferenced (State);

      Print_Rest_As_Is (Element);
      Control := Terminate_Immediately;
   end An_If_Expression_Path_Pre_Op;

end GNATPP.Pre_Operations;
