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

with Heap;
with LexTokenManager;
with SeqAlgebra;

--# inherit Heap,
--#         LexTokenManager,
--#         SeqAlgebra,
--#         Statistics,
--#         SystemErrors;

--  This package extends the package SeqAlgebra to support
--  Lex_String. This package uses case insensitive comparison betweeen
--  strings.
package LexTokenManager.Seq_Algebra is

   type Seq is private;

   type Member_Of_Seq is private;

   -- Returns true only if S is a null seq
   function Is_Null_Seq (S : Seq) return Boolean;

   -- Returns true only if M is a null member (not in any sequence or set)
   function Is_Null_Member (M : Member_Of_Seq) return Boolean;

   -- Returns the first member of the given Seq S.  The returned member
   -- can be used as a starting point to iterate through all members of the
   -- sequence or set.
   function First_Member (The_Heap : Heap.HeapRecord;
                          S        : Seq) return Member_Of_Seq;

   -- Next member of the sequence or set.  A null member will be returned if the
   -- sequence or set has no more members.
   -- Successively calling Next_Member with the previously returned Member
   -- (starting with the member returned from First_Member) will iterate over
   -- all members of the sequence or set provided no elements are added or
   -- removed from the sequence or set during the iteration over its elements.
   function Next_Member (The_Heap : Heap.HeapRecord;
                         M        : Member_Of_Seq) return Member_Of_Seq;

   -- Initializes Seq S ready for use.  It must be called prior to any
   -- other Sequence or Set operation.
   procedure Create_Seq (The_Heap : in out Heap.HeapRecord;
                         S        :    out Seq);
   --# global in out Statistics.TableUsage;
   --# derives S,
   --#         The_Heap              from The_Heap &
   --#         Statistics.TableUsage from *,
   --#                                    The_Heap;

   -- Returns true only if the Sequence or Set S is empty.
   function Is_Empty_Seq (The_Heap : Heap.HeapRecord;
                          S        : Seq) return Boolean;

   -- SeqAlgebra uses the Heap package for storage.  The storage must be
   -- released by calling Dispose before all references (there may be aliases)
   -- to the sequence or set within The_Heap are out of scope.
   -- WARNING: Disposing of a Seq S may leave Members of S with invalid
   -- references to non-existent elements. Do not use Members from a disposed
   -- Seq.
   -- As a rule Member objects of a set S should not have a larger scope than S.
   procedure Dispose_Of_Seq (The_Heap : in out Heap.HeapRecord;
                             S        : in     Seq);
   --# derives The_Heap from *,
   --#                       S;

   -------- Functions and operations intended for sequences --------

   -- Returns a pseudo-member which can be used to prefix new elements to a
   -- sequence.  Appending to the pseudo-member will place the appended member
   -- at the head of the sequence.
   -- The caller must ensure that the sequence S is properly Created.
   -- The returned member is guaranteed to be non null and deemed to refer
   -- to the pseudo element of S.
   function Before_First_Member (S : Seq) return Member_Of_Seq;

   -- Inserts the GivenValue in a sequence referenced by M after member M.
   -- M must not be null.
   -- If the call is successful the new value of M refers to the appended
   -- element.
   procedure Append_After
     (The_Heap    : in out Heap.HeapRecord;
      M           : in out Member_Of_Seq;
      Given_Value : in     LexTokenManager.Lex_String);
   --# global in out Statistics.TableUsage;
   --# derives M,
   --#         Statistics.TableUsage from *,
   --#                                    The_Heap &
   --#         The_Heap              from *,
   --#                                    Given_Value,
   --#                                    M;

   -- Gets the (Natural) value of the member M.
   -- The Member must be non null.
   -- The value returned is undefined if M is the pseudo member obtained
   -- from a call to Before_First_Member.
   function Value_Of_Member (The_Heap : Heap.HeapRecord;
                             M        : Member_Of_Seq) return LexTokenManager.Lex_String;

   -- If the Given_Value is not already an element of the set S add it to S.
   -- A Create operation must have been applied to S.
   -- WARNING: AddMember is only defined for a Seq object representing a set.
   -- If an element is added to a set it is in general indecidable as
   -- to whether it will be included in any current iteration over the elements
   -- of the set using Next_Member.
   procedure Add_Member (The_Heap    : in out Heap.HeapRecord;
                         S           : in     Seq;
                         Given_Value : in     LexTokenManager.Lex_String);
   --# global in     LexTokenManager.State;
   --#        in out Statistics.TableUsage;
   --# derives Statistics.TableUsage,
   --#         The_Heap              from *,
   --#                                    Given_Value,
   --#                                    LexTokenManager.State,
   --#                                    S,
   --#                                    The_Heap;

   -- If an element with Given_Value exists in S, remove it from S.
   -- A Create operation must have been applied to S.
   -- WARNING: RemoveMember is only defined for a Seq object representing a set.
   -- Removing an element from a Seq will render any members
   -- referencing the element invalid and they should not be used.
   -- There are no checks against this erroneous use.
   procedure Remove_Member (The_Heap    : in out Heap.HeapRecord;
                            S           : in     Seq;
                            Given_Value : in     LexTokenManager.Lex_String);
   --# global in LexTokenManager.State;
   --# derives The_Heap from *,
   --#                       Given_Value,
   --#                       LexTokenManager.State,
   --#                       S;

   -- Return true only if there is an element in S with the value Given_Value.
   -- WARNING: IsMember is only defined for a Seq object representing a set.
   function Is_Member
     (The_Heap    : Heap.HeapRecord;
      S           : Seq;
      Given_Value : LexTokenManager.Lex_String)
     return        Boolean;
   --# global in LexTokenManager.State;

   ----------- Set Operations on Seq representing Sets -----------

   -- Creates a new set C with all the values from set A and set B.
   -- The caller should not apply CreateSeq to C prior to invoking Union.
   -- Sets A and B are unchanged.
   -- Note if value Z is in A and B, it will only appear once in C.
   -- This is a set operation do not use with a Seq representing a sequence.
   procedure Union (The_Heap : in out Heap.HeapRecord;
                    A, B     : in     Seq;
                    C        :    out Seq);
   --# global in     LexTokenManager.State;
   --#        in out Statistics.TableUsage;
   --# derives C                     from The_Heap &
   --#         Statistics.TableUsage,
   --#         The_Heap              from *,
   --#                                    A,
   --#                                    B,
   --#                                    LexTokenManager.State,
   --#                                    The_Heap;

   -- An in place Union, all elements in set B are added to set
   -- A with no duplicates.  B is unchanged.
   -- This is a set operation do not use with a Seq representing a sequence.
   procedure Augment_Seq (The_Heap : in out Heap.HeapRecord;
                          A, B     : in     Seq);
   --# global in     LexTokenManager.State;
   --#        in out Statistics.TableUsage;
   --# derives Statistics.TableUsage,
   --#         The_Heap              from *,
   --#                                    A,
   --#                                    B,
   --#                                    LexTokenManager.State,
   --#                                    The_Heap;

   -- This is an "in-place" Complement: all elements
   -- are removed from A if they are also in B. B is unchanged.
   -- This is a set operation do not use with a Seq representing a sequence.
   procedure Reduction (The_Heap : in out Heap.HeapRecord;
                        A, B     : in     Seq);
   --# global in LexTokenManager.State;
   --# derives The_Heap from *,
   --#                       A,
   --#                       B,
   --#                       LexTokenManager.State;

   procedure Debug (The_Heap : in Heap.HeapRecord;
                    S        : in Seq);
   --# derives null from S,
   --#                   The_Heap;

private

   type Seq is record
      The_Seq : SeqAlgebra.Seq;
   end record;

   type Member_Of_Seq is record
      Member : SeqAlgebra.MemberOfSeq;
   end record;

end LexTokenManager.Seq_Algebra;
