-------------------------------------------------------------------------------
--
--  This file is part of AdaBrowse.
--
-- <STRONG>Copyright (c) 2002 by Thomas Wolf.</STRONG>
-- <BLOCKQUOTE>
--    AdaBrowse is free software; you can redistribute it and/or modify it
--    under the terms of the  GNU General Public License as published by the
--    Free Software  Foundation; either version 2, or (at your option) any
--    later version. AdaBrowse is distributed in the hope that it will be
--    useful, but <EM>without any warranty</EM>; without even the implied
--    warranty of <EM>merchantability or fitness for a particular purpose.</EM>
--    See the GNU General Public License for  more details. You should have
--    received a copy of the GNU General Public License with this distribution,
--    see file "<A HREF="GPL.txt">GPL.txt</A>". If not, write to the Free
--    Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
--    USA.
-- </BLOCKQUOTE>
--
-- <DL><DT><STRONG>
-- Author:</STRONG><DD>
--   Thomas Wolf  (TW)
--   <ADDRESS><A HREF="mailto:twolf@acm.org">twolf@acm.org</A></ADDRESS></DL>
--
-- <DL><DT><STRONG>
-- Purpose:</STRONG><DD>
--   Offers <CODE>Item_Table</CODE>s and indices on them. Used by
--   <A HREF="ad-scanner.html">AD.Scanner</A>: it gets all items of interest
--   in an item list, builds one or more indices on it, and then traverses
--   these indices to output items.
--   <BR><BR>
--   The point of this distinction is that items may be grouped: an item may
--   reference subordinate items (such as representation clauses or pragmas
--   belonging to this item), and indices usually only contain the indices of
--   the top-level items. An index alone makes no sense, it is only useful in
--   conjunction with its associated <CODE>Item_Table</CODE>.
--   <BR><BR>
--   Yes, this is not a very safe arrangement, but it is sufficient for my
--   purposes in the context of AdaBrowse. Also, it is quite a hack: this
--   package was born as an extract from stuff I had temporarily within
--   AD.Scanner, and it hasn't really been cleaned up. It's more a means to
--   split up the huge package AD.Scanner than a true proper decomposition.
--   </DL>
--
-- <!--
-- Revision History
--
--   17-FEB-2002   TW  Initial version.
-- -->
-------------------------------------------------------------------------------

pragma License (GPL);

with Asis;
with Asis.Text;

with Asis2.Spans;

with AD.Descriptions;

package AD.Item_Lists is

   type Comment_Span;
   type Comment_Ptr is access Comment_Span;
   type Comment_Span is
      record
         Span : Asis.Text.Span;
         Next : Comment_Ptr;
      end record;
   --  Since an item may have several comments, we need to store a list of
   --  comments.

   type Item_Desc is
      record
         Is_Clause  : Boolean;
         --  True only for the pseudo-item for the context clauses. It is the
         --  only item for which 'From' and 'To' are set.
         Element    : Asis.Element;
         --  The Asis element this item refers to. A Nil_Element if 'Is_Clause'
         --  is True.
         From, To   : Asis2.Spans.Position;
         --  If 'Is_Clause' is True, 'From' is the beginning of the first
         --  context clause, and 'To' is the end of the last context clause.
         Class      : AD.Descriptions.Item_Classes;
         --  The item's class: a high-level grouping allowing us to make
         --  broad distinctions. Otherwise, we'd always have to use several
         --  different *_Kind functions to find out what we have.
         Finder     : Natural;
         --  The current index within 'Finders'. Only for internal use!
         Finders    : AD.Descriptions.Finders_Ptr;
         --  A pointer to the definition of comment finders for the item. Only
         --  for internal use.
         List       : Comment_Ptr;
         --  The list of comments associated with this item.
         Belongs_To : Integer := 0;
         --  Only top-level items have 'Belongs_To' = 0. Any subordinate item
         --  has an index to some other item (meaningful only within the same
         --  <CODE>Item_Table</CODE>) to which it belongs.
         Is_Private : Boolean := False;
         --  Set to True for items in the private part of a container.
         Done       : Boolean := False;
         --  Unused.
         Idx        : Natural := 0;
         --  The original index of the item (again, meaningful only within
         --  a particular <CODE>Item_Table</CODE>). We use this sometimes to
         --  make sorting maintain the original source ordering.
         Sub        : Natural := 0;
         --  If /= 0, the index of the first subordinate item. Again, meaning-
         --  ful only within a particular <CODE>Item_table</CODE>.
         Next       : Natural := 0;
         --  If /= 0, the item is a subordinate item and 'Next' is the link
         --  to the next subordinate item belonging to 'Belongs_To'. A zero
         --  terminates the list.
      end record;

   type Item_Table  is array (Positive range <>) of Item_Desc;

   type Index_Table is array (Positive range <>) of Integer;
   --  'Integer' instead of 'Natural' because we sometimes use negative
   --  indices to distinguish between references to two different tables.
   --  Can happen for containers, where some of the contained items belong
   --  to the containing element.

   procedure Sort_Index
     (Items : in     Item_Table;
      Index : in out Index_Table);
   --  Sorts the index on 'Items' such that all visible items come before any
   --  private items; within each of these, exceptions < constants < objects <
   --  the rest; "the rest" is sorted such that the original source ordering
   --  is maintained.

   procedure Sort_By_Name
     (Items : in     Item_Table;
      Index : in out Index_Table);
   --  Sort the index on 'Items' by name.

   procedure Sort_Subordinates
     (Index           : in out Index_Table;
      Items           : in     Item_Table;
      Contained_Items : in     Item_Table);
   --  Sort the index, which is supposed to an index of subordinate items from
   --  'Items' and 'Contained_Items' and which shall contain only pragmas and
   --  representation clauses such that all rep clauses come before any
   --  pragmas, and both are soted by name. Negative indices in the index are
   --  take to refer to 'Contained_Items', positive ones to 'Items'. See also
   --  function <CODE>Collect_Subordinates</CODE>.

   function Find_Items
     (The_Unit : in Asis.Compilation_Unit)
     return Item_Table;
   --  Return an <CODE>Item_Table</CODE> for a library unit. If there are
   --  context clauses, the first item in the returned table has 'Is_Clause'
   --  set to True. The next item is the item for the library unit declaration.
   --  Any following items are library unit pragmas belonging to this library
   --  unit. The result is already grouped!

   function Find_Items
     (Decl : in Asis.Declaration)
     return Item_Table;
   --  'Decl' must be a container. Returns all items within the container
   --  (only the visible items if it is a (generic) package). The resulting
   --  list is *not* grouped yet!

   procedure Clear_Table
     (Table : in out Item_Table);
   --  Frees any storage allocated for comment lists for the items in the
   --  table.

   procedure Group_Items
     (Items         : in out Item_Table;
      For_Container :    out Natural);
   --  Sets up the 'Sub' chains as needed. Any pragma in 'Items' that refers
   --  to the enclosing container is put on a chain rooted in 'For_Container'.
   --  'For_Container' is zero if no such item exists in 'Items'. Call this
   --  before getting an index! (As I said, this whole interface is not very
   --  clean...)

   function Build_Index
     (Items : in Item_Table)
     return Index_Table;
   --  Returns an index for 'Items' containing only the top-level items, i.e.
   --  those that are not subordinates of any other item.

   function Collect_Subordinates
     (Items           : in Item_Table;
      Contained_Items : in Item_Table;
      Current         : in Natural;
      For_Container   : in Natural := 0)
     return Index_Table;
   --  Returns an index of all elements on the chains rooted at
   --  Items (Current).Sub and For_Container. The resulting index spans
   --  both 'Items' and 'Contained_Items' (from 'For_Container'); indices
   --  referring to 'Contained_Items' are negative in the index.

end AD.Item_Lists;

