------------------------------------------------------------------------------
--                                                                          --
--                            GNATPP COMPONENTS                             --
--                                                                          --
--                        G N A T P P . L A Y O U T                         --
--                                                                          --
--                                 S p e c                                  --
--                                                                          --
--                    Copyright (C) 2001-2012, 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, MA 02110-1301, USA.                                              --
--                                                                          --
-- GNATPP is maintained by AdaCore (http://www.adacore.com)                 --
--                                                                          --
------------------------------------------------------------------------------

--  This package contains the routines used to detect the desired layout
--  of the components of the result code

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

package GNATPP.Layout is

   type Layout_Info is record
      Pos1  : Natural;
      Pos2  : Natural;
      Pos3  : Natural;

      Flag1 : Boolean;
      Flag2 : Boolean;
      Flag3 : Boolean;
      Flag4 : Boolean;
      Flag5 : Boolean;
   end record;
   --  This type describes the layout of a given ASIS Element.
   --  Natural components define the positions of some subcomponent lexems,
   --  Boolean flags define some specific variants of the layout of the
   --  syntax construct. The exact meaning of the fields depends on the
   --  Element kind and is defined by the corresponding access and update
   --  routines. (This type is supposed to be used as a component of the
   --  Traversal_Step_Record containing also the component for the ASIS
   --  Element to which the given layout should be applied).

   Nil_Layout_Info : constant Layout_Info :=
     (Pos1  => 0,
      Pos2  => 0,
      Pos3  => 0,

      Flag1 => False,
      Flag2 => False,
      Flag3 => False,
      Flag4 => False,
      Flag5 => False);

   procedure Compute_Aggregate_Layout (E : Asis.Element);
   --  Computes the layout of the association Elements being components of the
   --  argument aggregate Element. Is applied to the aggregate Element
   --  itself. Also works exactly in the same way on A_Discriminant _Constraint
   --  elements which in respect of layout are similar to record aggregates
   --
   --  Sets the result into Current_State.Layout
   --
   --  Setting of the layout parameters have the following meaning:
   --
   --  -  Pos1 - start position for a component association
   --  -  Pos2 - start position for an arrow in named associations
   --  -  Pos3 - not used
   --
   --  - Flag1 - start each component association from the new line
   --  - Flag2 - Flag5 - not used

   procedure Compute_Call_Layout (E : Asis.Element);
   --  Computes the layout of a procedure call, an entry call and a prefix
   --  function call and a pragma (pragmas are similar to prefix calls in
   --  respect of syntax)
   --
   --  Sets the result into Current_State.Layout
   --
   --  Setting of the layout parameters have the following meaning:
   --
   --  -  Pos1 - start position for a parameter association
   --  -  Pos2 - start position for an arrow in named associations
   --  -  Pos3 - Start of the call if the whole call has to be moved left
   --
   --  -  Flag1 - start each parameter association from the new line
   --  -  Flag2 - move all the call left to fit the line length limitation
   --  -  Flag3 - Flag5 - not used
   --
   --  ??? We compute and set Pos3 and Flag2, but they are not used now???

   procedure Compute_Parameter_Layout;
   --  Computes the layout of A_Parameter_Specification Elements. Is applied to
   --  parameter specifications and sets the layout info for the enclosing
   --  construct.
   --
   --  ??? May be, we should change this procedure to apply it to the construct
   --  containing parameter specifications?
   --
   --  Sets the result into Layout record of the enclosing construct
   --  containing the given parameter specification
   --
   --  Setting of the layout parameters have the following meaning:
   --
   --  -  Pos1 - colon position
   --  -  Pos2 - assignment sign position
   --
   --  -  Pos3 - not used
   --
   --  -  Flag1 - start each parameter specification from the new line
   --
   --  -  Flag2  - Flag5 - not used

   procedure Compute_Generic_Actuals_Layout;
   --  Starting from the first generic association, computes the layout of
   --  all the associations in the instantiation. Note, that this procedure is
   --  called only if we already know that we should place associations on
   --  separate lines. So all what it computes is the alignment of the arrow
   --  delimiter.
   --
   --  Note also, that we compute the instantiation layout not for the
   --  instantiation element, but for the (first) instantiation. The reason for
   --  this is that in the instantiation we have too many lexems before the
   --  first association.
   --
   --  The layout info is set not to the association element but one level up -
   --  for the instantiation element
   --
   --  Setting of the layout parameters have the following meaning:
   --
   --  -  Pos2 - start position for an arrow in named associations
   --
   --  All the other fields and flags are not used.

   procedure Compute_Context_Clauses_Alignment
     (Clause_Elements : Asis.Element_List;
      Use_Pos         : out Natural);
   --  Analyzes the list of with and use clauses and computes the layout
   --  parameter for aligning use clauses in 'with - use' pairs.
   --  The caller is responsible to provide Elements parameter containing the
   --  with and use clauses only.

   procedure Compute_Declarations_Alignment
     (Start_Pos  :     Natural;
      Elements   :     Asis.Element_List;
      Colon_Pos  : out Natural;
      Assign_Pos : out Natural);
   --  Analyzes the list of declarations and computes the layout parameters for
   --  aligning colons (Colon_Pos) and assignment signs (Assign_Pos). Start_Pos
   --  should be set by the caller and it should be the starting position of
   --  the declarations in the list.
   --  The caller is responsible to provide Elements parameter containing only
   --  the declarations which should really be aligned, that is, number or
   --  object declarations or record component declarations.

   procedure Compute_Assign_Statement_Alignment
     (Start_Pos  :     Natural;
      Elements   :     Asis.Element_List;
      Assign_Pos : out Natural);
   --  Analyzes the list of assignment statements and computes the layout
   --  parameter for aligning assignment signs (Assign_Pos). Start_Pos
   --  should be set by the caller and it should be the starting position of
   --  the statements in the list.
   --  The caller is responsible to provide Elements parameter containing the
   --  assignment statements only

   procedure Compute_Component_Clause_Alignment
     (Start_Pos  :     Natural;
      Elements   :     Asis.Element_List;
      At_Pos     : out Natural);
   --  Analyzes the list of component clauses and computes the layout
   --  parameter for aligning the 'at' keyword (At_Pos). Start_Pos
   --  should be set by the caller and it should be the starting position of
   --  the component clauses in the list.
   --  The caller is responsible to provide Elements parameter containing the
   --  record representation clauses only

   procedure Compute_Obj_Decl_Layout (E : Asis.Element);
   --  Computes the layout of a declaration having the general syntax
   --   <list of names> : <definition> [:= init_Expression]
   --
   --  Sets the result into Current_State.Layout
   --
   --  Settings of the layout parameters have the following meaning:
   --
   --  -  Pos1 - Pos3 - not used
   --
   --  - Flag1 - start the definition from the new line
   --  - Flag2 - start the expression from the new line
   --  - Flag3  - Flag5 - not used
   --
   --  (Possible extension: for a very long list of defining names which can
   --  not fit one line:
   --
   --  - Flag3 - start each defining name from the new line)

   procedure Compute_Infix_Call_Layout (E : Asis.Element);
   --  Computes the layout of an infix function call. This procedure "unwinds"
   --  the hierarchical structure of the call and consider it in the same
   --  way as RM 95 gives the expression syntax in 4.4 (that is,
   --
   --    operand {operation operand}
   --
   --  Setting of the layout parameters have the following meaning:
   --
   --  -  Pos1 - start position for an operand
   --  -  Pos2 - start position for an operation sign ??? (not implemented yet)
   --  -  Pos3 - not used
   --
   --  - Flag1 - start each operand from the new line
   --  - Flag2 - start each operation sign the new line ???  (not implemented
   --            yet)
   --  - Flag3  - Flag5 - not used

   procedure Compute_Enum_Def_Layout (E : Asis.Element);
   --  Computes the layout of an enumeration type definition.
   --
   --  Sets the result into Current_State.Layout
   --
   --  Setting of the layout parameters have the following meaning:
   --
   --  -  Pos1 - Pos3 - not used
   --
   --  - Flag1 - start each enumeration literal definition from the new line
   --  - Flag2 - Flag5 - not used

   procedure Compute_Case_Choices_Layout (E : Asis.Element);
   --  Computes the layout of the choices in case path and in a variant. Also
   --  processes choices in component associations. Probably, we have to rename
   --  the routine.
   --
   --  Sets the result into Current_State.Layout
   --
   --  Setting of the layout parameters have the following meaning:
   --
   --  -  Pos1 - the start position of the choice
   --
   --  -  Pos2 - the position of the '|' delimiter (they are supposed to be
   --            aligned if we have more than one choice each on a separate
   --            line
   --
   --  - Pos3 - not used
   --
   --  - Flag1 - start each choice from the new line
   --
   --  - Flag2 - Flag4 - not used
   --
   --  - Flag5 - the choice list contains '|' and these '|' are aligned. We
   --            need this information to decide how to align the arrow
   --            delimiter following the list of choices

   procedure Compute_Simple_Expression_Range_Layout (E : Asis.Element);
   --  Computes the layout of a simple expression range
   --
   --  Sets the result into Current_State.Layout
   --
   --  Setting of the layout parameters have the following meaning:
   --
   --  -  Pos1 - not used now, may be used as a start position for the right
   --            expression
   --
   --  - Pos2 - Pos3 - not used
   --
   --  - Flag1 - start the lower bound expression from the new line
   --  - Flag2 - start the upper_bound expression from the new line
   --
   --  - Flag3 - Flag5 - not used

   procedure Compute_Discriminants_Layout (E : Asis.Element);
   --  Computes the layout of a known discriminant part
   --
   --  Sets the result into Current_State.Layout
   --
   --  Setting of the layout parameters have the following meaning:
   --
   --  - Pos1 - Pos3 - not used
   --
   --  - Flag1 - start each discriminant specification from the new line
   --
   --  - Flag2 - Flag5 - not used

   procedure Compute_Array_Definition_Layout (E : Asis.Element);
   --  Computes the layout of a constrained or unconstrained array definition
   --
   --  Sets the result into Current_State.Layout
   --
   --  Setting of the layout parameters have the following meaning:
   --
   --  - Pos1 - Pos3 - not used
   --
   --  - Flag1 - start the definition from the new line
   --
   --  - Flag2 - start each index definition from the new line
   --
   --  - Flags - Flag5 - not used

   function Short_Circuit_Padding return Positive;
   --  This function computes the indentation of 'and then' or 'or else'
   --  in case if we have to start these keywords from the new line.

   ----------------------
   -- Access functions --
   ----------------------

   function Enum_Literal_Def_On_Separate_Lines return Boolean;
   --  ???

   function Is_And_Then_Arg return Boolean;
   function Is_Or_Else_Arg return Boolean;
   --  These functions are supposed to be called for An_Expression Elements.
   --  They check from the info stored in Current_State if the expression is
   --  the argument is the short circuit argument

   function Is_First_Par_Association return Boolean;
   --  Is supposed to be called (in post-op) when the current element is a
   --  parameter association. Checks from the info stored in Current_State if
   --  this is the first association

   function Generic_Associations_On_Separate_Lines return Boolean;
   --  Is supposed to be called for a generic association. Reads from the
   --  enclosing instantiation element if the associations should be on
   --  separate lines

   function Assign_Start_Pos return Natural;
   function Colon_Start_Pos  return Natural;
   --  Return the position of a colon and assignment sign in parameter
   --  specifications

   function Choice_On_Separate_Line return Boolean;
   function Choice_Start_Pos        return Natural;
   function Vert_Line_Start_Pos     return Natural;
   --  These functions are supposed to be applied to an element being a choice
   --  in case path, record variant or exception handler (???). They are
   --  supposed to return the corresponding components of the layout info.

   function Align_Arrow_As_Vert_Line return Boolean;
   --  Checks if the arrow delimiter should be aligned as a vertical line
   --  delimiter. This may happen if we have a list of choices separated by the
   --  vertical line

   function Enclosing_Association_Start_Pos return Natural;
   --  Is supposed to be applied to a function call in the situation when
   --  it is a part of some enclosing call. It returns the start position of
   --  the enclosing associations (which for sure should be started from the
   --  new line.

   function Start_Range_Expression_From_New_Line return Boolean;
   function Start_Upper_Range_Expression_From_New_Line return Boolean;
   --  Tests if the current element is the simple expression range which should
   --  be started from the new line. The first function checks both lower and
   --  upper bounds of the range, the second one checks only the upper bound
   --  and it always return False for the lower bound. Also work on discrete
   --  simple expression ranges

   function Discriminants_On_Separate_Lines return Boolean;
   --  Says if the discriminant specification should be started from a
   --  separate line. May be applied to the whole known discriminant part, to a
   --  discriminant specification and to the discriminant defining name.
   --  Extracts the information from previously computed layout info.

   function Start_Array_Def_From_New_Line return Boolean;
   --  Tests if the array definition (which is supposed to be the current
   --  element) should be started from the new line

   function Start_Index_Def_From_New_Line return Boolean;
   --  Determines if the code immediately following '(', ',' or ')' is an
   --  index definition in some array definition (or the component definition
   --  for ')') and if it is, checks if this code should be started from the
   --  new line (reading this from the corresponding layout info).

   function Start_Aggregate_From_New_Line return Boolean;
   --  Checks if the aggregate (or a discriminant constraint that is similar to
   --  a record aggregate in respect to layout) should be started form the new
   --  line

   function Impose_Extra_Indentation return Boolean;
   --  Is supposed to be called for a record definition. Checks if extra
   --  indentation level is used for record layout ???

   -------------------------------------
   -- Layout info set/update routines --
   -------------------------------------

   procedure Set_Is_And_Then_Arg;
   procedure Set_Is_Or_Else_Arg;
   --  Stores in the Current_State layout info if the current element is the
   --  short circuit argument

   procedure Set_Is_First_Par_Association;
   --  Stores in the Current_State layout info if the current element (which
   --  should be a parameter association) is the first association in the call

   procedure Set_Generic_Arrow_Start_Pos (Position : Natural);
   --  Is supposed to be called when the current element is the (first) generic
   --  association. Stores in the layout info for the whole instantiation the
   --  position of the arrow delimiter

   procedure Set_Generic_Associations_On_Separate_Lines;
   --  Is supposed to be called when the current element in an instantiation,
   --  and when it has been detected that the associations should be on
   --  separate lines. Sets Flag1 in Current_State on to indicate this
   --  layout feature.

   procedure Set_Assign_Start_Pos (Position : Natural);
   procedure Set_Colon_Start_Pos  (Position : Natural);
   --  Are supposed to be called when the current element represents the first
   --  parameter association. Stores the corresponding layout info for the
   --  enclosing construct containing this parameter

   procedure Set_Impose_Extra_Indentation;
   --  Is supposed to be called when the current element is a record
   --  definition. Stores in the current layout info if the record layout
   --  needs extra indentation for record components (Sets Flag1 ON)

   -------------------------------
   -- Old stuff, needs revising --
   -------------------------------

   --  ??? Is this the right place for these functions?

   function Get_Enclosing_Element
     (Step_Up : Natural := 0)
      return   Asis.Element;
   function Get_Enclosing_Kind
     (Step_Up : Natural := 0)
      return   Flat_Element_Kinds;
   --  Return Enclosing_Element or its kind, taking it from the stack. If
   --  Step_Up is not zero, the function goes Step_Up steps up the syntax
   --  hierarchy

   --  Aggregates and discriminant constraints:
   function Comp_Asctns_On_Sep_Lines return Boolean;
   function Comp_Asctns_Start_Pos    return Natural;
   --  ???

   function Arrow_Start_Pos          return Natural;
   --  This function should be applied to all forms of associations!

   --  Elements having parameters? Parameter specifications?
   function Par_Spec_On_Separate_Lines return Boolean;

   --  Procedure, entry and (prefix) function calls:
   function Pars_On_Sep_Lines                        return Boolean;
   function Move_All_Call_Left                       return Boolean;
   function Start_Par_Pos (Step_Down : Natural := 0) return Natural;
   --  When applied to a parameter association, Step_Down should be 0, when
   --  applied to formal parameter names and actual parameters, it hould be
   --  set to 1
   function Start_Call_Pos                           return Natural;

   --  Component, object and number declarations

   --  Definitions of the form
   --   <list of names> : <definition> [:= init_Expression]

   function Init_Expr_On_Separate_Line  return Boolean;

   ----------------------------
   -- Layout update routines --
   ----------------------------

   --  Do we really need the update routines?
   --  At the moment, some of these functions update the layout info in
   --  the top element of the traversal stack, and some of them updates
   --  the layout info in Current_State (which is supposed to be put in the
   --  stack later.
   --
   --  ??? Is this the right approach? Should we try to have more unified
   --  way of storing the layout info?

   --  Aggregates:
   procedure Set_Comp_Asctns_On_Sep_Lines (Separate_Line : Boolean);
   procedure Set_Comp_Asctns_Start_Pos    (Position      : Natural);
   procedure Set_Arrow_Start_Pos          (Position      : Natural);
   --  This procedure should be applied to all forms of associations!

   --  Elements having parameters? Parameter specifications?
   procedure Set_Par_Spec_On_Sep_Lines (Separate_Line : Boolean);

   --  Procedure, entry and (prefix) function calls:
   procedure Set_Pars_On_Sep_Lines  (Separate_Line : Boolean);
   procedure Set_Move_All_Call_Left (Move_It       : Boolean);
   procedure Set_Start_Par_Pos      (Position      : Natural);
   procedure Set_Start_Call_Pos     (Position      : Natural);

end GNATPP.Layout;
