-------------------------------------------------------------------------------
-- (C) Altran Praxis Limited
-------------------------------------------------------------------------------
--
-- The SPARK toolset is free software; you can redistribute it and/or modify it
-- under terms of the GNU General Public License as published by the Free
-- Software Foundation; either version 3, or (at your option) any later
-- version. The SPARK toolset is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-- Public License for more details. You should have received a copy of the GNU
-- General Public License distributed with the SPARK toolset; see file
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy of
-- the license.
--
--=============================================================================

--------------------------------------------------------------------------------
--  RefList
--
--  Purpose:
--    RefList is a utility package which is used to associate a node on the
--    syntax tree with a dependency relation or a list of referenced variables.
--    It is a higher-level wrapper around the Heap package.
--
--    The Examiner, particularly the flow analyser, needs to know what
--    information flows are associated with particular syntax nodes.
--    For example, the node of an assignment statement will have an export
--   (the assigned var) and 0 or more imports (the referenced variables in the
--    assigned expression).  Some nodes, notably Conditions, will have a list
--    of referenced variables but no exports.
--
--    Rather than store the dependency information in the syntax tree where it
--    is only required for a small percentage of the nodes it is placed in a
--    RefList.
--
--    The association between a symbol table node and its dependencies in a
--    Reflist object is via a hash table with the look up based on the syntax
--    tree node number.
--
--    It is the HashTable abstract data type which is visible in the
--    specification and to which all the operations (methods) apply.
--
--    The actual RefList information is stored in the Heap and is not directly
--    accessible.  The methods defined in this package must be used to manage
--    the information.
--
--    The RefList package contains two procedures which are not directly
--    related to the main purpose of the package described above:
--      ExpandSeq and ExpandToComponentEntities,
--    these procedures are concerned with expanding a list of objects to include
--    all components of records appearing in the list.
--
--    ExpandToComponentEntities uses the HashTable object for a compilation
--    unit to expand every RefList to include component names of records
--    referenced in it.
--
--  Clients:
--    RefList is used by Sem to build the dependency lists and by the
--    FlowAnalyser to inspect the dependencies.
--
--    ExpandSeq and ExpandToComponentEntities are only used by the FlowAnalyser.
--
--  Use:
--    An example of use the main use of RefLists:
--      MainLoop.adb calls RefList.Init to initialize a HashTable object;
--      Sem-CompUnit-WalkStatements-WF_Assign.adb adds a relation to a RefList
--        by calling RefList.AddRelation with the initialized HashTable object.
--      FlowAnalyser.FlowAnalyse.adb calls RefList.FirstExport and
--      RefList.NextExport to iterate through the exports and calls
--      RefList.DependencyRelation to obtain the dependencies associated with
--      each export.
--
--    For an example of the use of ExpandSeq and ExpandToComponentEntities see
--      FlowAnalyser-FlowAnalyse as this is the only module which calls these
--      procedures.
--
--    Important principles are:
--
--      1. a HashTable object must be Initialized before it used;
--
--      2. RefList is a wrapper for Heap and if the Heap becomes
--         exhausted of free storage elements an attempt to perform any of the
--         operations of this package will cause termination with a fatal
--         error.  As this may occur the methods of RefList are not
--         guaranteed to terminate.
--
--  Extension:
--    It is not expected that any extension will be made to this package.
--
--------------------------------------------------------------------------------

with ComponentManager;
with Dictionary;
with Heap;
with SeqAlgebra;
with STree;

use type Heap.Atom;

--# inherit ComponentManager,
--#         Dictionary,
--#         ExaminerConstants,
--#         Heap,
--#         SeqAlgebra,
--#         SP_Symbols,
--#         Statistics,
--#         STree,
--#         SystemErrors;
package RefList is
   -- HashTable is the ADT which maintains the association between syntax
   -- tree nodes and the sets of variables stored within The_Heap.
   type HashTable is private;

   -- Initializes the mapping between syntax nodes and sets to an empty
   -- relation.  This must be called before using the HashTable, Table.
   procedure Init (Table : out HashTable);
   --# derives Table from ;

   -- Procedure to add Export and associated list of imports to hash table.
   -- Create a set from the Imports and TheExport and associate the given
   -- syntax tree node, Node, with the new set.
   -- Node must be a non null Syntax Tree node, Imports must be a non null
   -- Seq (although the sequence may be empty) and TheExport may be
   -- any dictionary symbol including a NullSymbol
   -- (representing derives null from Imports).
   -- BEWARE: AddRelation only makes a shallow copy of Imports;
   -- a reference (an alias) to Imports is created and therefore the
   -- corresponding actual parameter must not be disposed using
   -- SeqAlgebra.DisposeSeq.
   procedure AddRelation
     (Table     : in out HashTable;
      TheHeap   : in out Heap.HeapRecord;
      Node      : in     STree.SyntaxNode;
      TheExport : in     Dictionary.Symbol;
      Imports   : in     SeqAlgebra.Seq);
   --# global in out Statistics.TableUsage;
   --# derives Statistics.TableUsage from *,
   --#                                    Node,
   --#                                    Table,
   --#                                    TheExport,
   --#                                    TheHeap &
   --#         Table                 from *,
   --#                                    Node,
   --#                                    TheHeap &
   --#         TheHeap               from *,
   --#                                    Imports,
   --#                                    Node,
   --#                                    Table,
   --#                                    TheExport;

   -- Associates an empty set with the given syntax tree node, Node.
   -- Node must be non null.
   procedure AddNullRelation (Table   : in out HashTable;
                              TheHeap : in out Heap.HeapRecord;
                              Node    : in     STree.SyntaxNode);
   --# global in out Statistics.TableUsage;
   --# derives Statistics.TableUsage,
   --#         Table,
   --#         TheHeap               from *,
   --#                                    Node,
   --#                                    Table,
   --#                                    TheHeap;

   -------------extractor functions and procedures---------------------------

   -- Returns true only if the given Node in the syntax tree has one or more
   -- exported variables.  Node must be non null.
   function NodeHasExportList
     (Table   : in HashTable;
      TheHeap : in Heap.HeapRecord;
      Node    : in STree.SyntaxNode)
     return    Boolean;

   -- True only if the given Export is dependent on one or more variables.
   -- The Atom representing the exported variable, The_Export, must be non null.
   function ExportHasDependencies (TheExport : in Heap.Atom;
                                   TheHeap   : in Heap.HeapRecord) return Boolean;

   -- Provides a starting point for iterating through the set of Exported
   -- variables associated with a node (in an unspecified but repeatable order).
   -- It obtains the first Exported variable in the sequence.
   -- The Node must be non null and either represent a node with the dependency
   -- relation derives ; or a node which has at least one exported variable.
   procedure FirstExport
     (Table     : in     HashTable;
      TheHeap   : in     Heap.HeapRecord;
      Node      : in     STree.SyntaxNode;
      TheExport :    out Heap.Atom);
   --# derives TheExport from Node,
   --#                        Table,
   --#                        TheHeap;
   -- pre "node represents 'derives ;'" or else NodeHasExportList (Table, TheHeap, Node);

   -- Provides the means to successively iterate over the set of exported
   -- variables.  It returns the next variable in the sequence from TheExport
   -- (the order is unspecified but repeatable).
   -- TheExport must refer to an Exported variable.
   -- If there are no more Exported variables in the set a Heap.NullPointer
   -- is returned.
   function NextExport (TheHeap   : Heap.HeapRecord;
                        TheExport : Heap.Atom) return Heap.Atom;

   -- Returns a set of Imported variables on which The_Export depends.
   -- The_Export must refer to an Exported variable which has imported
   -- variables on which it is dependent.
   -- BEWARE: Only a shallow copy of the set of imported variables is returned.
   -- The returned value should be regarded as strictly read only unless it is
   -- intended to update the set associated with the syntax tree node.
   function DependencyList (TheHeap   : Heap.HeapRecord;
                            TheExport : Heap.Atom) return SeqAlgebra.Seq;
   -- pre ExportHasDependencies (TheExport, TheHeap);

   -- Some nodes of the syntax tree have no exported variables associated with
   -- them, for instance, conditional expressions in an if statement.
   -- In such cases there will usually be variables which are referenced in the
   -- expression and these are recorded in a set associated with the node.
   -- This subprogram provides a reference to the set of variables referenced
   -- by the syntax tree node, Node.
   -- Node must be non null and be a node which has no associated Exported
   -- variables.
   -- On successful completion Seq is guaranteed to be non null although
   -- it may be empty.
   procedure ReferencedVarList
     (Table   : in     HashTable;
      TheHeap : in     Heap.HeapRecord;
      Node    : in     STree.SyntaxNode;
      Seq     :    out SeqAlgebra.Seq);
   --# derives Seq from Node,
   --#                  Table,
   --#                  TheHeap;
   -- pre not NodeHasExportList (Table, TheHeap, Node);

   -- On completion the set Seq is one of the following depending on
   -- the sort of syntax tree node represented by Node:
   -- (1) For a node with a null derives list: empty set
   -- (2) For a node with no exports but a referenced variable list:
   --        the referenced variables
   -- (3) For a node with one or more exports: the union of the imports which
   --        affect each export
   -- Node must be non null.
   -- On completion Seq is guaranteed to be non null but it may be empty.
   procedure AllReferencedVariables
     (Table   : in     HashTable;
      TheHeap : in out Heap.HeapRecord;
      Node    : in     STree.SyntaxNode;
      Seq     :    out SeqAlgebra.Seq);
   --# global in out Statistics.TableUsage;
   --# derives Seq,
   --#         TheHeap               from Node,
   --#                                    Table,
   --#                                    TheHeap &
   --#         Statistics.TableUsage from *,
   --#                                    Node,
   --#                                    Table,
   --#                                    TheHeap;

   ------------- Record Component Expansion procedures---------------------------

   -- ExpandSeq extends a list of variables given by TheSeq to include the
   -- components of all record variables named in the list.
   procedure ExpandSeq
     (ComponentData : in     ComponentManager.ComponentData;
      TheSeq        : in     SeqAlgebra.Seq;
      TheHeap       : in out Heap.HeapRecord);
   --# global in     Dictionary.Dict;
   --#        in out Statistics.TableUsage;
   --# derives Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    ComponentData,
   --#                                    Dictionary.Dict,
   --#                                    TheHeap,
   --#                                    TheSeq;

   -- This procedure analyses the hash table, Table, (associated with a
   -- compilation unit) and iterates over each entry in the Table.
   -- For each entry representing a syntax node with dependencies:
   --   determine if the node has a dependency relation or a list of imports,
   --   if it has a dependency relation, then for each export expand the RefList
   --     of imports,
   --   if it only has a list of variables then expand the RefList of variables.
   -- Expansion extends the RefList to include the components of all record
   -- variables named in the list.
   procedure ExpandToComponentEntities
     (ComponentData : in     ComponentManager.ComponentData;
      Table         : in     HashTable;
      TheHeap       : in out Heap.HeapRecord);
   --# global in     Dictionary.Dict;
   --#        in     STree.Table;
   --#        in out Statistics.TableUsage;
   --# derives Statistics.TableUsage,
   --#         TheHeap               from *,
   --#                                    ComponentData,
   --#                                    Dictionary.Dict,
   --#                                    STree.Table,
   --#                                    Table,
   --#                                    TheHeap;

private
   -- The hash function is a modulus of HashMax.
   HashMax : constant Integer := 25500;
   subtype HashIndex is Integer range 0 .. HashMax;
   type HashTable is array (HashIndex) of Natural;
end RefList;
