-------------------------------------------------------------------------------
-- (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.
--
--=============================================================================

--------------------------------------------------------------------------------
--  Cells
--
--  Purpose:
--
--  This package provides an ADT for a Heap of Cells.
--
--  The heap is used to build the primary linked
--  data structures used by the VCG, including DAGs
--  representing FDL expressions, predicate/action pairs,
--  stacks of cells, and so on.
--
--  Clients:
--
--  The Examiner's VC Generator components use this package to build
--  higher-level ADTs (CStacks, CLists, Pile, Pairs, Labels, Graph,
--  Structures).  The DAGs representing FDL are built by the DAG
--  package and its subunits, particular DAG.BuildGraph, DAG.BuildExpnDAG,
--  and DAG.BuildAnnotationExpnDAG.
--
--  The Graph package sits at the top of this tree, and represents the
--  Basic-Path Graph of a subprogram during VC Generation.
--
--  Use:
--
--  A client should first declare and Initalize a Cells.Heap_Record object.
--
--  Cells are then allocated using Create_Cell.  Attributes can be set using
--  the various Set_* procedures below.
--
--  Extension:
--     None planned.
--------------------------------------------------------------------------------
with Cell_Storage;
with Dictionary;
with LexTokenManager;
with SP_Symbols;

use type Cell_Storage.Cell;
use type Cell_Storage.Cell_Kind;

--# inherit Cell_Storage,
--#         Dictionary,
--#         ExaminerConstants,
--#         LexTokenManager,
--#         SP_Symbols,
--#         Statistics,
--#         SystemErrors;

package Cells is
   -- See package Cell_Storage for description
   -- of these types
   subtype Cell_Kind is Cell_Storage.Cell_Kind;

   subtype Cell is Cell_Storage.Cell;
   Null_Cell : constant Cell := Cell'First;

   subtype Cell_Rank is Cell_Storage.Cell_Rank;
   Unknown_Rank : constant Cell_Rank := Cell_Rank'First;

   -- A collection from which Cells may be allocated
   type Heap_Record is private;

   --=================================================================
   -- Constructor procedure for Heap_Record
   --=================================================================

   procedure Initialize (Heap : out Heap_Record);
   --# derives Heap from ;

   --=================================================================
   -- Accessor functions that yield useful properties of a Heap_Record
   -- and Cells
   --
   -- Note - these are declared here, so may be used later in
   -- pre- and post-conditions
   --=================================================================

   function Are_Identical (Cell_1, Cell_2 : Cell) return Boolean;
   --# return Cell_1 = Cell_2;

   -- returns the value of the Kind attribute for CellName
   function Get_Kind (Heap     : Heap_Record;
                      CellName : Cell) return Cell_Kind;

   -- Returns the value of the Free attribute for CellName
   function Is_Free (Heap     : Heap_Record;
                     CellName : Cell) return Boolean;

   function Is_Null_Cell (CellName : Cell) return Boolean;
   --# return CellName = Null_Cell;

   function Is_Const_Cell (Heap     : Heap_Record;
                           CellName : Cell) return Boolean;
   --# return Get_Kind (Heap, CellName) = Cell_Storage.Manifest_Const or
   --#   Get_Kind (Heap, CellName) = Cell_Storage.Named_Const;

   function Is_Reference_Cell (Heap     : Heap_Record;
                               CellName : Cell) return Boolean;
   --# return Get_Kind (Heap, CellName) = Cell_Storage.Reference;

   -- Returns Cell_Name as a numeric value.  Can be used
   -- to print the value of a Cell object e.g. for debugging.
   function Cell_Ref (Cell_Name : in Cell) return Natural;

   --=================================================================
   -- Constructor and Accessor functions for each Cell attribute
   --=================================================================

   -- Get_Kind is declared above

   procedure Set_Kind (Heap      : in out Heap_Record;
                       CellName  : in     Cell;
                       KindConst : in     Cell_Kind);
   --# derives Heap from *,
   --#                   CellName,
   --#                   KindConst;
   --# post Get_Kind (Heap, CellName) = KindConst;

   --------------------------------------------------------------
   -- Each Cell has three attributes that may be used to
   -- refer to other Cells.  These are called A_Ptr, B_Ptr
   -- and C_Ptr respectively.
   function Get_A_Ptr (Heap     : Heap_Record;
                       CellName : Cell) return Cell;

   function Get_B_Ptr (Heap     : Heap_Record;
                       CellName : Cell) return Cell;

   function Get_C_Ptr (Heap     : Heap_Record;
                       CellName : Cell) return Cell;

   procedure Set_A_Ptr (Heap           : in out Heap_Record;
                        Cell_1, Cell_2 : in     Cell);
   --# derives Heap from *,
   --#                   Cell_1,
   --#                   Cell_2;
   --# post Get_A_Ptr (Heap, Cell_1) = Cell_2;

   procedure Set_B_Ptr (Heap           : in out Heap_Record;
                        Cell_1, Cell_2 : in     Cell);
   --# derives Heap from *,
   --#                   Cell_1,
   --#                   Cell_2;
   --# post Get_B_Ptr (Heap, Cell_1) = Cell_2;

   procedure Set_C_Ptr (Heap           : in out Heap_Record;
                        Cell_1, Cell_2 : in     Cell);
   --# derives Heap from *,
   --#                   Cell_1,
   --#                   Cell_2;
   --# post Get_C_Ptr (Heap, Cell_1) = Cell_2;

   --------------------------------------------------------------

   -- The "Value" attribute of a Cell can either be set to
   -- a Natural or a Dictionary.Symbol type, using the
   -- procedures below.  It is entirely up to the caller
   -- to remember which type has been set (and therefore which
   -- type to subsequently access) depending on the context.

   function Get_Natural_Value (Heap     : Heap_Record;
                               CellName : Cell) return Natural;

   procedure Set_Natural_Value (Heap     : in out Heap_Record;
                                CellName : in     Cell;
                                Value    : in     Natural);
   --# derives Heap from *,
   --#                   CellName,
   --#                   Value;
   --# post Get_Natural_Value (Heap, CellName) = Value;

   function Get_Symbol_Value (Heap     : Heap_Record;
                              CellName : Cell) return Dictionary.Symbol;

   procedure Set_Symbol_Value (Heap     : in out Heap_Record;
                               CellName : in     Cell;
                               Sym      : in     Dictionary.Symbol);
   --# derives Heap from *,
   --#                   CellName,
   --#                   Sym;
   --# post Get_Symbol_Value (Heap, CellName) = Sym;

   --------------------------------------------------------------

   function Get_Rank (Heap     : Heap_Record;
                      CellName : Cell) return Cell_Rank;

   procedure Set_Rank (Heap     : in out Heap_Record;
                       CellName : in     Cell;
                       Rank     : in     Cell_Rank);
   --# derives Heap from *,
   --#                   CellName,
   --#                   Rank;
   --# post Get_Rank (Heap, CellName) = Rank;

   --------------------------------------------------------------

   function Get_Copy (Heap     : Heap_Record;
                      CellName : Cell) return Cell;

   -- There is no Set_Copy operation for the Copy attribute.
   -- This is instead set by the Copy_Contents and
   -- Create_Copy operations below.

   --------------------------------------------------------------

   function Get_Op_Symbol (Heap     : Heap_Record;
                           CellName : Cell) return SP_Symbols.SP_Symbol;

   procedure Set_Op_Symbol (Heap     : in out Heap_Record;
                            CellName : in     Cell;
                            Sym      : in     SP_Symbols.SP_Symbol);
   --# derives Heap from *,
   --#                   CellName,
   --#                   Sym;
   --# post Get_Op_Symbol (Heap, CellName) = Sym;

   --------------------------------------------------------------

   function Get_Lex_Str (Heap     : Heap_Record;
                         CellName : Cell) return LexTokenManager.Lex_String;

   procedure Set_Lex_Str (Heap     : in out Heap_Record;
                          CellName : in     Cell;
                          Str      : in     LexTokenManager.Lex_String);
   --# derives Heap from *,
   --#                   CellName,
   --#                   Str;
   --# post Get_Lex_Str (Heap, CellName) = Str;

   --------------------------------------------------------------

   function Get_Assoc_Var (Heap     : in Heap_Record;
                           CellName : in Cell) return Dictionary.Symbol;

   procedure Set_Assoc_Var (Heap     : in out Heap_Record;
                            CellName : in     Cell;
                            VarSym   : in     Dictionary.Symbol);
   --# derives Heap from *,
   --#                   CellName,
   --#                   VarSym;
   --# post Get_Assoc_Var (Heap, CellName) = VarSym;

   --------------------------------------------------------------

   -- Returns the value of the Boolean Marked attribute for CellName
   function Is_Marked (Heap     : Heap_Record;
                       CellName : Cell) return Boolean;

   procedure Mark_Cell (Heap     : in out Heap_Record;
                        CellName : in     Cell);
   --# derives Heap from *,
   --#                   CellName;
   --# post Is_Marked (Heap, CellName);

   procedure UnMark_Cell (Heap     : in out Heap_Record;
                          CellName : in     Cell);
   --# derives Heap from *,
   --#                   CellName;
   --# post not Is_Marked (Heap, CellName);

   --=================================================================
   -- Methods
   --=================================================================

   --------------------------------------------------------------
   -- Allocates a new Cell on the Heap.
   --------------------------------------------------------------
   procedure Create_Cell (Heap     : in out Heap_Record;
                          CellName :    out Cell);
   --# global in out Statistics.TableUsage;
   --# derives CellName,
   --#         Heap                  from Heap &
   --#         Statistics.TableUsage from *,
   --#                                    Heap;
   --# post CellName /= Null_Cell; -- if normal termination of this procedure

   --------------------------------------------------------------
   -- Copies the following attributes of Source to Destination
   --   A_Ptr
   --   B_Ptr
   --   Kind
   --   Rank
   --   Lex_Str
   --   Op_Symbol
   --   Val
   --   Assoc_Var
   -- Other attributes in Destination are unmodified
   --------------------------------------------------------------
   procedure Copy_Contents (Heap                : in out Heap_Record;
                            Source, Destination : in     Cell);
   --# derives Heap from *,
   --#                   Destination,
   --#                   Source;

   --------------------------------------------------------------
   -- Allocates a new Cell using Create_Cell, and copies
   -- the following attributes of CellName to it:
   --  Kind
   --  Rank
   --  Lex_Str
   --  Op_Symbol
   --  Val
   --  Assoc_Var
   --
   -- The "Copy" attribute of CellName is then set to refer
   -- to the newly created Cell.
   --------------------------------------------------------------
   procedure Create_Copy (Heap     : in out Heap_Record;
                          CellName : in     Cell);
   --# global in out Statistics.TableUsage;
   --# derives Heap                  from *,
   --#                                    CellName &
   --#         Statistics.TableUsage from *,
   --#                                    Heap;

   --------------------------------------------------------------
   -- Returns CellName to the Heap's free list
   --------------------------------------------------------------
   procedure Dispose_Of_Cell (Heap     : in out Heap_Record;
                              CellName : in     Cell);
   --# derives Heap from *,
   --#                   CellName;

   --------------------------------------------------------------
   -- Sets state of Statistics package to record
   -- the current high-water mark of TheHeap
   --------------------------------------------------------------
   procedure Report_Usage (TheHeap : in Heap_Record);
   --# global in out Statistics.TableUsage;
   --# derives Statistics.TableUsage from *,
   --#                                    TheHeap;

   --=================================================================
   -- Debugging
   --=================================================================

   --------------------------------------------------------------
   -- Returns the current size of the vector.
   --------------------------------------------------------------
   function Get_Heap_Size (Heap : in Heap_Record) return Cell_Storage.Cell;

private
   subtype Cell_Content is Cell_Storage.Cell_Content;

   type Heap_Record is record
      High_Mark      : Cell;
      Next_Free_Cell : Cell;
      List_Of_Cells  : Cell_Storage.Vector;
   end record;

end Cells;
